home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / tde210.zip / TDEASM.C < prev    next >
C/C++ Source or Header  |  1992-11-13  |  96KB  |  2,413 lines

  1. /*
  2.  * In the DTE 5.1 editor, the end of file was marked with '\0'.  I have
  3.  * decided to use ^Z to mark the begin and end of files instead of '\0'.
  4.  * That way, null characters are allowed as normal text characters.  ^Z is used
  5.  * to mark the end of strings in buffers instead of '\0'.  The standard C
  6.  * string library functions should not be used when dealing with text buffers.
  7.  *
  8.  * The often used string routines have been rewritten in assembly.  When using
  9.  * 16 bit processors, accessing memory by WORDs on WORD boundaries is twice
  10.  * as fast as accessing memory by BYTEs.  If a memory pointer is even then it
  11.  * is WORD aligned.  If a memory pointer is odd, do the first BYTE and then
  12.  * the rest of the string is WORD aligned on an even boundary.
  13.  *
  14.  *  See:
  15.  *
  16.  *     Intel, _80286 and 80287 Programmer's Reference Manual_, Santa Clara,
  17.  *     California, 1987, ISBN 1-55512-055-5, page 2-3:
  18.  *
  19.  *       "Note that a word need not be aligned at an even-numbered byte
  20.  *        address.  This allows maximum flexibility in data structures
  21.  *        (e.g.,records containing mixed byte and word entries) and
  22.  *        efficiency in memory utilization.  Although actual transfers
  23.  *        of data between the processor and memory take place at physically
  24.  *        aligned word boundaries, the 80286 converts requests for
  25.  *        unaligned words into the appropriate sequences of requests
  26.  *        acceptable to the memory interface.  Such odd aligned words
  27.  *        transfers, however, may impact performance by requiring two
  28.  *        memory cycles to transfer the word rather than one.  Data
  29.  *        structures (e.g., stacks) should therefore be designed in such
  30.  *        a way that word operands are aligned on word boundaries whenever
  31.  *        possible for maximum system performance."
  32.  *
  33.  *
  34.  * See also:
  35.  *
  36.  *     Intel, _80386 Programmer's Reference Manual_, Santa Clara,
  37.  *     California, 1986, ISBN 1-55512-022-9, page 2-4:
  38.  *
  39.  *       "Note that words need not be aligned at even-numbered addresses
  40.  *        and doublewords need not be aligned at addresses evenly divisible
  41.  *        by four.  This allows maximum flexibility in data structures
  42.  *        (e.g., records containing mixed byte, word, and doubleword
  43.  *        items) and efficiency in memory utilization.  When used in a
  44.  *        configuration with a 32-bit bus, actual transfers of data between
  45.  *        processor and memory take place in units of doublewords beginning
  46.  *        at addresses evenly divisible by four; however, the processor
  47.  *        converts requests for misaligned words or doublewords into the
  48.  *        appropriate sequences of requests acceptable to the memory
  49.  *        interface.  Such misaligned data transfers reduce performance
  50.  *        by requiring extra memory cylces.  For maximum performance,
  51.  *        data structures (including stacks) should be designed in such
  52.  *        a that, whenever possible, word operands are aligned at even
  53.  *        addresses and doubleword operands are aligned at addresses evenly
  54.  *        divisible by four."
  55.  *
  56.  *
  57.  * Two routines were written to adjust the string pointers whenever they
  58.  * approach the end of a segment, cpf() and cpb() (check pointer foward and
  59.  * check pointer backward).  With these two routines, the code may be
  60.  * compiled without the huge memory model.  Another assembly routine was
  61.  * written to compare physical memory locations, ptoul().  For example,
  62.  * all of these pointers point to same physical memory address:
  63.  *
  64.  *         59a1:9122 == 58a1:a122 == 62a1:0122  = physical address 404,274
  65.  *
  66.  * An efficient way to compare far pointers is to convert them to either
  67.  * unsigned long or long integers.  Either one will do - their is no such
  68.  * thing a negative physical memory address.  A long int goes from
  69.  * -2 billion to 2 billion, which leaves plenty of room to describe a physical
  70.  * address, using a long, where the max is 1 MEG.  I used unsigned long.  When
  71.  * adding or subtracting from the physical address of a pointer, we should
  72.  * never, ever get a negative physical address.  This is the concept behind the
  73.  * function ptoul(), which is short for pointer to unsigned long.
  74.  *
  75.  * With these functions written in assembly, this editor is fairly fast.
  76.  * I feel the need for speed.
  77.  *
  78.  * New editor name:  TDE, the Thomson-Davis Editor.
  79.  * Author:           Frank Davis
  80.  * Date:             June 5, 1991, version 1.0
  81.  * Date:             July 29, 1991, version 1.1
  82.  * Date:             October 5, 1991, version 1.2
  83.  * Date:             January 20, 1992, version 1.3
  84.  * Date:             February 17, 1992, version 1.4
  85.  * Date:             April 1, 1992, version 1.5
  86.  * Date:             June 5, 1992, version 2.0
  87.  * Date:             October 31, 1992, version 2.1
  88.  *
  89.  * This modification of Douglas Thomson's code is released into the
  90.  * public domain, Frank Davis.  You may distribute it freely.
  91.  */
  92.  
  93. #include "tdestr.h"
  94. #include "common.h"
  95. #include "tdefunc.h"
  96.  
  97.  
  98. /*
  99.  * Name:    cpf - check_pointer_forward
  100.  * Purpose: To adjust a pointer if it is nearing end of a segment (within 16k)
  101.  * Date:    June 5, 1991
  102.  * Passed:  s:  string pointer
  103.  * Notes:   To avoid a bunch of code generated for pointer arithmetic when using
  104.  *          the huge memory model, this routine adjusts a pointer when it
  105.  *          approaches the end of a segment.
  106.  */
  107. text_ptr cpf( text_ptr s )
  108. {
  109.    _asm {
  110.         mov     ax, WORD PTR s  ; get OFFSET of s
  111.         mov     dx, WORD PTR s+2        ; get SEGMENT of s
  112.         cmp     ax, 0xc000      ; are we within 16k of top of segment?
  113.         jb      get_out         ; no, get out
  114.         sub     ax, 0x8000      ; yes, subtract 32k from offset
  115.         add     dx, 0x0800      ; add 0x0800 paragraphs to segment == 32k
  116.         ALIGN   2
  117. get_out:
  118.    }
  119. }
  120.  
  121.  
  122. /*
  123.  * Name:    cpb - check_pointer_backward
  124.  * Purpose: To adjust a pointer if it is nearing beginning of a segment (16k)
  125.  * Date:    June 5, 1991
  126.  * Passed:  s:  string pointer
  127.  * Notes:   To avoid a bunch of code generated for pointer arithmetic when using
  128.  *          the huge memory model, this routine adjusts a pointer when it
  129.  *          approaches the beginning of a segment.  Don't check NULL pointer.
  130.  */
  131. text_ptr cpb( text_ptr s )
  132. {
  133.    _asm {
  134.         mov     ax, WORD PTR s  ; get OFFSET of s
  135.         mov     dx, WORD PTR s+2        ; get SEGMENT of s
  136.         cmp     ax, 0           ; is offset of s == NULL?
  137.         jne     not_null        ; no, check pointer
  138.         cmp     dx, 0           ; is segment of s == NULL?
  139.         je      get_out         ; yes, don't check NULL pointer
  140.         ALIGN   2
  141. not_null:
  142.         cmp     ax, 0x4000      ; are we within 16k of beginning of segment?
  143.         jae     get_out         ; no, get out
  144.         add     ax, 0x8000      ; yes, add 32k to offset
  145.         sub     dx, 0x0800      ; sub 0x0800 paragraphs from segment == 32k
  146.         ALIGN   2
  147. get_out:
  148.    }
  149. }
  150.  
  151.  
  152. /*
  153.  * Name:    ptoul - pointer to unsigned long
  154.  * Purpose: convert a far pointer to unsigned long integer
  155.  * Date:    June 5, 1991
  156.  * Passed:  s:  a far pointer
  157.  * Notes:   combine the offset and segment like so:
  158.  *                offset       0000
  159.  *                segment   + 0000
  160.  *                          =======
  161.  *                            00000
  162.  *          result is returned in dx:ax
  163.  */
  164. unsigned long ptoul( void far *s )
  165. {
  166.    _asm {
  167.         mov     ax, WORD PTR s          ; ax = OFFSET of s
  168.         mov     dx, WORD PTR s+2        ; dx = SEGMENT of s
  169.         mov     bx, dx          ; put copy of segment in bx
  170.         mov     cl, 12          ; cl = decimal 12 - shift hi word 3 hex digits
  171.         shr     dx, cl          ; convert to 'real segment'
  172.         mov     cl, 4           ; cl = 4  - shift hi word 1 hex digit left
  173.         shl     bx, cl          ; shift bx - to add 3 digits of seg to 4 of off
  174.         add     ax, bx          ; add low part of segment to offset
  175.         adc     dx, 0           ; if carry, bump to next 'real' segment
  176.    }
  177. }
  178.  
  179.  
  180. /*
  181.  * Name:    nptos - normalize pointer to segment
  182.  * Purpose: make the offset of a pointer no larger than a paragraph (16 bytes)
  183.  * Date:    June 5, 1991
  184.  * Passed:  s:  string pointer
  185.  * Notes:   move all but the paragraph from the offset of the pointer to the
  186.  *          segment.   The offset will be no larger than 16 bytes. Why? because
  187.  *          we can add up to 0xFFF0 reliably to a pointer in small, compact or
  188.  *          large model and not worry about segment wrap.
  189.  *
  190.  *                offset       abcx
  191.  *                segment     0000
  192.  *                          =======
  193.  *                offset       000x
  194.  *                segment     0abc
  195.  *          result is returned in dx:ax
  196.  */
  197. text_ptr nptos( text_ptr s )
  198. {
  199.    _asm {
  200.         mov     ax, WORD PTR s          ; ax = OFFSET of s
  201.         mov     dx, WORD PTR s+2        ; dx = SEGMENT of s
  202.         mov     bx, ax          ; put copy of offset in bx
  203.         mov     cl, 4           ; cl = 4  - shift lo word 1 hex digit
  204.         shr     bx, cl          ; shift bx - line up on paragraph
  205.         add     dx, bx          ; add hi part of offset to segment
  206.         and     ax, 0x000f      ; mask out three hex digits in offset
  207.    }
  208. }
  209.  
  210.  
  211. /*
  212.  * Name:    addltop - add long to pointer
  213.  * Purpose: add long integer to a pointer
  214.  * Date:    June 5, 1991
  215.  * Passed:  l: long
  216.  *          p: text pointer
  217.  * Returns: pointer + long integer
  218.  * Notes:   A long integer takes two WORDs.  A far pointer takes two WORDs.
  219.  *          A long integer cannot be added directly to a far pointer.
  220.  *              This diagram may help explain better than I can write.
  221.  *
  222.  *          far pointer            0000   offset
  223.  *                                0xxx    segment
  224.  *                                  +
  225.  *          long integer       00000000             throw away those three
  226.  *                                ======            hex digits on long integer,
  227.  *                                 0000   offset    they have no effect
  228.  *           new far pointer      0xxx    segment
  229.  *
  230.  *          msw = Most Significant WORD
  231.  *          lsw = Least Significant WORD
  232.  *
  233.  *          When working with the long integer, we don't need to worry about
  234.  *          the three x's on segment of the pointer.  Add or subtract the lsw
  235.  *          of the long integer to/from the offset.  If there is a carry,
  236.  *          it only affects the left most digit of the msw of the pointer.
  237.  */
  238. text_ptr addltop( long l, text_ptr p )
  239. {
  240.  
  241.    if (l >= 0) {
  242.       _asm {
  243.         mov     ax, WORD PTR p          ; ax = OFFSET of p
  244.         mov     dx, WORD PTR p+2        ; dx = SEGMENT of p
  245.         mov     bx, WORD PTR l+2        ; msw of l in bx
  246.         add     ax, WORD PTR l          ; add offset of p and lsw of l
  247.         adc     bx, 0           ; if carry, pointer in another segment
  248.         mov     cl, 12          ; cl = 12 - shift off 3 hex digits
  249.         shl     bx, cl          ; consider the 1st hex digit of msw of l
  250.         add     dx, bx          ; add segment of p and 1st digit of msw of l
  251.       }
  252.    } else {
  253.       l = -l;      /* convert l to positive and subtract from pointer p */
  254.       _asm {
  255.         mov     ax, WORD PTR p          ; ax = OFFSET of p
  256.         mov     dx, WORD PTR p+2        ; dx = SEGMENT of p
  257.         mov     bx, WORD PTR l+2        ; msw of l in bx
  258.         mov     cl, 12                  ; cl = 12 - shift off 3 hex digits
  259.         sub     ax, WORD PTR l          ; subtract low part of pointer
  260.         adc     bx, 0                   ; if we borrowed then add it back to bx
  261.         shl     bx, cl                  ; only handle 1st hex digit of msw of l
  262.         sub     dx, bx                  ; subtract msw from segment of p
  263.       }
  264.    }
  265. }
  266.  
  267.  
  268. /*
  269.  * Name:    find_CONTROL_Z - assembler version, see commented C at end
  270.  * Purpose: To determine the length of a line up to ^Z
  271.  * Date:    June 5, 1991
  272.  * Passed:  s: the line to be measured
  273.  * Notes:   DOS carried over ^Z to mark the end of files from CP/M.  Since
  274.  *          it is the only character not allowed in regular text files.  ^Z
  275.  *          can be used, instead of '\0', to mark the end of strings.  All
  276.  *          ASCII characters, except ^Z, may be included in a text file.
  277.  *          However, none of the C string library functions should be used
  278.  *          when working with text.  The string library functions can be used
  279.  *          on responses solicited from the user.
  280.  * Returns: the length of the line
  281.  */
  282. unsigned int  find_CONTROL_Z( text_ptr s )
  283. {
  284.    s = cpf( s );
  285.    _asm {
  286.         mov     dx, ds          ; keep ds in dx, MUST save data segment
  287.         push    si              ; put copy of si on stack
  288.  
  289.         xor     cx, cx          ; cx = 0
  290.         mov     si, WORD PTR s  ; put OFFSET of s in si
  291.         mov     ax, WORD PTR s+2        ; get SEGMENT of s
  292.         mov     ds, ax          ; else, segment in ds
  293.         cmp     si, 0           ; is offset of s == NULL?
  294.         jne     not_null        ; no, find length
  295.         cmp     ax, 0           ; is segment of s == NULL?
  296.         je      get_out         ; yes, line length = 0
  297.         ALIGN   2
  298. not_null:
  299.         mov     bl, CONTROL_Z   ; keep Control Z in bl - eos marker
  300.         mov     ax, si          ; pointer is ok, check for word align
  301.         shr     ax, 1           ; if [si] is odd, lsb is 1 - rotate to carry
  302.         jnc     top             ; see if string is WORD aligned
  303.         lodsb                   ; no, get a BYTE - now WORD aligned
  304.         cmp     al, bl          ; is ds:[si] == ^Z?
  305.         je      get_out         ; yes, have length, cx = 0
  306.         inc     cx              ; increment length variable
  307.         ALIGN   2
  308. top:
  309.         lodsw                   ; string is WORD aligned
  310.         cmp     al, bl          ; is lo BYTE == ^Z?
  311.         je      get_out         ; yes, we have length
  312.         inc     cx              ; no, increment counter
  313.         cmp     ah, bl          ; now test higher BYTE, is it ^Z?
  314.         je      get_out         ; yes, we have length
  315.         inc     cx              ; no, increment length
  316.         jmp     SHORT top       ; look at next two characters
  317.         ALIGN   2
  318. get_out:
  319.         mov     ax, cx          ; put length in ax - as defined by Microsoft
  320.         mov     ds, dx          ; get back data segment from dx
  321.         pop     si              ; get back si from stack
  322.    }
  323.  
  324. /*
  325. int len = 0;
  326.  
  327.    while (*s != ^Z) {
  328.       ++len;
  329.       ++s;
  330.    }
  331.    return len;
  332. */
  333. }
  334.  
  335.  
  336. /*
  337.  * Name:    linelen - assembler version, see commented C at end of routine
  338.  * Purpose: To determine the length of a line, up to either a \n or a
  339.  *           ^Z, whichever comes first.
  340.  * Date:    June 5, 1991
  341.  * Passed:  s: the line to be measured
  342.  * Notes:   Demonstrates 'lodsb' and 'lodsw'.  Memory operations are most
  343.  *           efficient when working with WORDs.  See if first BYTE in
  344.  *           string is WORD aligned.  If it is then work with WORDs else
  345.  *           get the first BYTE and rest of string will be WORD aligned.
  346.  *           The 'mov' instruction could have been used, but 'lobsb' and
  347.  *           'lodsw' automatically increment the memory pointer.
  348.  * Returns: the length of the line
  349.  */
  350. unsigned int  linelen( text_ptr s )
  351. {
  352.    s = cpf( s );
  353.    _asm {
  354.         mov     dx, ds          ; keep ds in dx, MUST save data segment
  355.         push    si              ; save si on stack
  356.  
  357.         xor     cx, cx          ; cx = 0
  358.         mov     si, WORD PTR s  ; put OFFSET of s in si
  359.         mov     ax, WORD PTR s+2        ; get SEGMENT of s
  360.         mov     ds, ax          ; else, segment in ds
  361.         cmp     si, 0           ; is offset of s == NULL?
  362.         jne     not_null        ; no, find length
  363.         cmp     ax, 0           ; is segment of s == NULL?
  364.         je      get_out         ; yes, line length = 0
  365.         ALIGN   2
  366. not_null:
  367.         mov     bl, '\n'        ; keep new line character in bl
  368.         mov     bh, CONTROL_Z   ; keep Control Z in bh - DOS eof marker
  369.         mov     ax, si          ; pointer is ok, check for word align
  370.         shr     ax, 1           ; if [si] is odd, lsb is 1 - rotate to carry
  371.         jnc     top             ; see if string is WORD aligned
  372.         lodsb                   ; no, get a BYTE - now WORD aligned
  373.         cmp     al, bl          ; is BYTE == '\n'?
  374.         je      get_out         ; yes, have length, cx = 0
  375.         cmp     al, bh          ; is ds:[si] == ^Z?
  376.         je      get_out         ; yes, have length, cx = 0
  377.         inc     cx              ; increment length variable
  378.         ALIGN   2
  379. top:
  380.         lodsw                   ; string is WORD aligned
  381.         cmp     al, bl          ; test lower BYTE, is it '\n'
  382.         je      get_out         ; yes, we have length
  383.         cmp     al, bh          ; no, test for ^Z
  384.         je      get_out         ; yes, we have length
  385.         inc     cx              ; no, not '\n' or ^Z so increment counter
  386.         cmp     ah, bl          ; now test higher BYTE, is it '\n'
  387.         je      get_out         ; yes, we have length
  388.         cmp     ah, bh          ; is it ^Z
  389.         je      get_out         ; yes, we have length
  390.         inc     cx              ; no, not '\n' or ^Z so increment length
  391.         jmp     SHORT top       ; look at next two characters
  392.         ALIGN   2
  393. get_out:
  394.         mov     ax, cx          ; put length in ax - as defined by Microsoft
  395.         mov     ds, dx          ; get back data segment from dx
  396.         pop     si              ; get back si from stack
  397.    }
  398.  
  399. /*
  400. int len = 0;
  401.  
  402.    while (*s && *s != '\n') {
  403.       ++len;
  404.       ++s;
  405.    }
  406.    return len;
  407. */
  408. }
  409.  
  410.  
  411. /************* prelinelen is not used, but left in for reference **********/
  412. /*
  413.  * Name:    prelinelen
  414.  * Purpose: To determine the length of a line, from the current position
  415.  *           backwards to either a \n or a ^Z, whichever comes first.
  416.  * Date:    June 5, 1991
  417.  * Passed:  s: the line to be measured
  418.  * Returns: the length of the line up to the current position
  419.  * Notes:   It is assumed there will be a "terminating" ^Z before the
  420.  *           start of the first line.
  421.  */
  422. /*
  423. unsigned int prelinelen( text_ptr s )
  424. {
  425.    s = cpb( s );
  426.    _asm {
  427.         push    di              ; put copy of di on stack
  428.  
  429.         xor     ax, ax          ; ax = 0, keep string length in ax
  430.         mov     di, WORD PTR s  ; get offset of string
  431.         mov     dx, WORD PTR s+2        ; get segment of string
  432.         mov     es, dx          ; put segment in es
  433.         cmp     di, 0           ; is offset of string == NULL?
  434.         jne     not_null        ; no, do string stuff
  435.         cmp     dx, 0           ; is, segment of string == NULL?
  436.         je      get_out         ; yes, don't do NULL string
  437. not_null:
  438.         dec     di              ; look at previous character
  439. ALWORD: dec     di              ; get ready to check for WORD align
  440.         mov     bl, '\n'        ; keep '\n' in bl
  441.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  442.         mov     dx, di          ; pointer is ok, check for WORD align
  443.         shr     dx, 1           ; if [di] is odd, lsb is 1 - rotate to carry
  444.         jnc     top             ; string is WORD aligned
  445.         inc     di              ; fix the second decrement - see ALWORD
  446.         mov     dl, BYTE PTR es:[di]    ; get a BYTE - put in DL
  447.         cmp     dl, bl          ; is it '\n'
  448.         je      get_out         ; yes, get out - count = 0
  449.         cmp     dl, bh          ; is it ^Z
  450.         je      get_out         ; yes, get out - count = 0
  451.         inc     ax              ; increment length counter
  452.         dec     di              ; pointer was BYTE aligned, dec pointer
  453.         dec     di              ; pointer is now WORD aligned
  454.         ALIGN   2
  455. top:
  456.         mov     dx, WORD PTR es:[di]    ; load WORD - hi BYTE is next
  457.         cmp     dh, bl          ; is hi BYTE (next char) '\n'?
  458.         je      get_out         ; yes, get out - count already in ax
  459.         cmp     dh, bh          ; is hi BYTE (next char) ^Z?
  460.         je      get_out         ; yes, get out - count already in ax
  461.         inc     ax              ; increment character counter
  462.         cmp     dl, bl          ; now check lo BYTE, is it '\n'?
  463.         je      get_out         ; yes, get out - count is in ax
  464.         cmp     dl, bh          ; is lo BYTE ^Z?
  465.         je      get_out         ; yes, get out - count is in ax
  466.         inc     ax              ; increment character counter
  467.         dec     di              ; decrement pointer
  468.         dec     di              ; align pointer on WORD
  469.         jmp     SHORT top       ; test next 2 characters
  470. get_out:
  471.         pop     di              ; get back di from stack
  472.    }
  473. int len = 0;
  474.  
  475.    while (*--s != CONTROL_Z && *s != '\n')
  476.       ++len;
  477.    return len;
  478. }
  479. */
  480. /************************** prelinelen is not used ************************/
  481.  
  482.  
  483. /*
  484.  * Name:    find_next
  485.  * Purpose: To find the first character in the next line
  486.  * Date:    June 5, 1991
  487.  * Passed:  s: the starting point
  488.  * Returns: the first character in the next line
  489.  * Notes:   This function goes faster if machine works with WORDs.  See if
  490.  *           first BYTE in string is WORD aligned.  If it is not, get first
  491.  *           BYTE in string then the rest of string is WORD aligned.
  492.  *           Code added at end to adjust segment:offset if needed.
  493.  */
  494. text_ptr find_next( text_ptr s )
  495. {
  496.    _asm {
  497.         push    ds              ; save ds on stack
  498.         push    si              ; save si on stack
  499.  
  500.         mov     si, WORD PTR s          ; load OFFSET of s
  501.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  502.         mov     ds, ax
  503.         cmp     si, 0           ; is offset of string == NULL?
  504.         jne     not_null        ; no, do string stuff
  505.         cmp     ax, 0           ; is segment of string == NULL?
  506.         je      return_null     ; yes, return NULL if string is NULL
  507.         ALIGN   2
  508. not_null:
  509.         mov     bl, '\n'        ; keep '\n' in bl
  510.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  511.         mov     ax, si          ; move offset of si to ax
  512.         shr     ax, 1           ; shift right into carry flag
  513.         jnc     top             ; is string WORD aligned?
  514.         lodsb                   ; no, get a BYTE
  515.         cmp     al, bl          ; is it '\n'?
  516.         je      next_even       ; yes, si already incremented by lodsb
  517.         cmp     al, bh          ; is it ^Z?
  518.         je      return_null     ; yes, return NULL
  519.         ALIGN   2
  520. top:
  521.         lodsw                   ; string is WORD aligned, get two BYTEs
  522.         cmp     al, bl          ; is next BYTE == '\n'?
  523.         je      next_odd        ; yes, since si inc for WORD (lodsw) - dec di
  524.         cmp     al, bh          ; is next BYTE == ^Z?
  525.         je      return_null     ; yes, return NULL
  526.         cmp     ah, bl          ; is next BYTE in AH == '\n'?
  527.         je      next_even       ; yes, si is OK - return pointer to next BYTE
  528.         cmp     ah, bh          ; is next BYTE in AH == ^Z?
  529.         je      return_null     ; yes, return NULL
  530.         jmp     SHORT top       ; look at next WORD
  531.         ALIGN   2
  532. return_null:
  533.         xor     ax, ax          ; clear ax - offset = NULL
  534.         xor     dx, dx          ; clear dx - segment = NULL
  535.         jmp     SHORT get_out   ; return text_ptr in dx:ax - see Microsoft
  536.         ALIGN   2
  537. next_odd:
  538.         dec     si              ; 'lodsw' went one BYTE too far - so dec si
  539. next_even:
  540.         mov     ax, si          ; ds:si now points to next line, load ax
  541.         mov     dx, ds          ; load dx with segment of next BYTE
  542.         cmp     ax, 0xc000      ; are we within 16k of segment?
  543.         jb      get_out         ; no, get out
  544.         sub     ax, 0x8000      ; yes, subtract 32k from offset
  545.         add     dx, 0x0800      ; add 0x0800 paragraphs to segment
  546.         ALIGN   2
  547. get_out:
  548.         pop     si              ; get back si from stack
  549.         pop     ds              ; get back ds from stack
  550.    }
  551. /*
  552.    while (*s && *s != '\n' && *s != CONTROL_Z)
  553.       ++s;
  554.    if (*s)
  555.       return ++s;
  556.    else
  557.       return NULL;
  558. */
  559. }
  560.  
  561.  
  562. /*
  563.  * Name:    find_prev
  564.  * Purpose: To find the start of the previous line
  565.  * Date:    June 5, 1991
  566.  * Passed:  current: the current line
  567.  * Returns: the start if the previous line
  568.  * Notes:   current should be at the start of the current line.
  569.  *          There must be a ^Z preceding the first line.
  570.  *          This function goes faster if machine works with WORDs.  See if
  571.  *           first BYTE in string is WORD aligned.  If it is not, get first
  572.  *           BYTE in string then the rest of string is WORD aligned.
  573.  *           The test for '\n' will pass a lot more than the test for
  574.  *           ^Z.  Set up the WORD align stuff first.
  575.  *           Since we are searching, by WORDs, backwards, the hi BYTE is the
  576.  *           prev BYTE and the al BYTE is two prev BYTEs (make sense?).
  577.  *           Code added at end to adjust segment:offset if needed.
  578.  */
  579. text_ptr find_prev( text_ptr current )
  580. {
  581.    _asm {
  582.         push    di              ; save di on stack
  583.  
  584.         mov     di, WORD PTR current    ; load OFFSET of current
  585. DECR1:  dec     di                      ; decrement it
  586.         mov     ax, WORD PTR current+2  ; load SEGMENT of current
  587.         mov     es, ax
  588.         cmp     di, 0           ; is offset of string == NULL?
  589.         jne     not_null        ; no, do string stuff
  590.         cmp     ax, 0           ; is segment of string == NULL?
  591.         je      return_null     ; yes, return NULL if string NULL
  592.         ALIGN   2
  593. not_null:
  594.         mov     bl, '\n'        ; keep '\n' in bl
  595.         mov     bh, CONTROL_Z   ; keep ^Z in bh
  596.         mov     ax, di          ; put copy of offset in ax
  597.         shr     ax, 1           ; shift right thru carry flag
  598.         jnc     on_boundary     ; if no carry, string is WORD aligned
  599. ;
  600. ; if we were to dec the pointer twice, it would be WORD aligned with the
  601. ; '--current'  BYTE in the AH register.  if ^Z test fails, might as well
  602. ; test the BYTE in the AL register.
  603. ;
  604. DECR2:  dec     di              ; dec offset one more so it is WORD aligned
  605.         mov     ax, WORD PTR es:[di]    ; might as well load WORD
  606.         cmp     ah, bh          ; is prev BYTE ^Z?
  607.         je      return_null     ; yes, return NULL
  608. ;
  609. ; now we are in the for loop - see commented C code at bottom.
  610. ; 'on_boundary' is not part of the for loop so jump past it if needed.
  611. ;
  612.         cmp     al, bl          ; is prev BYTE '\n'?
  613.         je      inc_pointer     ; yes, increment the pointer and return
  614.         cmp     al, bh          ; is it ^Z?
  615.         je      inc_pointer     ; yes, increment the pointer and return
  616.         jmp     SHORT for_loop  ;no, pointer is now WORD aligned - do for loop
  617.         ALIGN   2
  618. ;
  619. ; the string ended on an odd boundary and the DECR1 has now aligned the
  620. ; string on a WORD.  if we load a WORD, the '--current' BYTE would be in the
  621. ; AL register.
  622. ;
  623. on_boundary:
  624.         mov     ax, WORD PTR es:[di]    ; load --current, aligned on WORD
  625.         cmp     al, bh          ; is --current ^Z?
  626.         je      return_null     ; yes, return NULL
  627. ;
  628. ; now we are in the for loop and string is guaranteed WORD aligned.
  629. ; IMPORTANT: there are 2 cases if the test for '\n' or ^Z pass.
  630. ;            1) AH passed, so di must be increment twice for '++current'
  631. ;            2) AL passed, inc di once for '++current'
  632. ;
  633.         ALIGN   2
  634. for_loop:
  635.         dec     di              ; decrement di twice so it will be
  636.         dec     di              ; WORD aligned
  637.         mov     ax, WORD PTR es:[di]    ; string is WORD aligned
  638.         cmp     ah, bl          ; is --current '\n'?
  639.         je      next_even       ; yes, increment di twice to return ++current
  640.         cmp     ah, bh          ; is --current ^Z?
  641.         je      next_even       ; yes, increment di twice to return ++current
  642.         cmp     al, bl          ; look at low part of WORD, is it '\n'?
  643.         je      inc_pointer     ; yes, increment di once to return ++current
  644.         cmp     al, bh          ; is low part of WORD ^Z?
  645.         je      inc_pointer     ; yes, increment di once to return ++current
  646.         jmp     SHORT for_loop  ; get next WORD
  647.         ALIGN   2
  648. return_null:
  649.         xor     ax, ax          ; clear ax - offset = NULL
  650.         xor     dx, dx          ; clear dx - segment = NULL
  651.         jmp     SHORT get_out   ; return text_ptr in dx:ax - see Microsoft
  652.         ALIGN   2
  653. next_even:
  654.         inc     di              ; di is a WORD too far - inc di
  655. inc_pointer:
  656.         inc     di              ; ++current
  657.         mov     ax, di          ; put offset in ax
  658.         mov     dx, es          ; put segment in dx, return dx:ax - Microsoft
  659.         cmp     ax, 0x4000      ; are we within 16k of segment?
  660.         jae     get_out         ; no, get out
  661.         add     ax, 0x8000      ; yes, add 32k to offset
  662.         sub     dx, 0x0800      ; sub 0x0800 paragraphs to segment
  663.         ALIGN   2
  664. get_out:
  665.         pop     di              ; get back di from stack
  666.    }
  667.  
  668. /*
  669.    if (*--current == ^Z)
  670.       return NULL;
  671.    for (;;) {
  672.       if (*--current == '\n' || *current == ^Z)
  673.          return ++current;
  674.    }
  675. */
  676. }
  677.  
  678.  
  679. /*
  680.  * Name:    update_line
  681.  * Purpose: Display the current line in window
  682.  * Date:    June 5, 1991
  683.  * Passed:  window:  pointer to current window
  684.  * Notes:   Show string starting at column zero and if needed blank rest
  685.  *            of line.  Put max_col in cx and count down.  When we run into
  686.  *            '\n', cx contains number of columns to blank out.  Use the
  687.  *            fast 'rep stosw' to clear the end of line.
  688.  *          The C routine was probably fast enough, but let's do some
  689.  *            assembly because it's so fun.
  690.  *          To handle line lengths longer than 255 characters,
  691.  *            block begin and end columns were changed from real
  692.  *            to virtual columns in this display routine.
  693.  */
  694. void update_line( WINDOW *window )
  695. {
  696. text_ptr text;      /* current character of orig begin considered */
  697. char far *screen_ptr;
  698. int off;
  699. int attr;
  700. int line;
  701. int col;
  702. int bcol;
  703. int bc, ec;
  704. int normal, block;
  705. int max_col;
  706. int block_line;
  707. int show_eol;
  708. int len;
  709. int c;
  710. long rline;
  711. file_infos *file;
  712.  
  713.    if (window->rline > window->file_info->length)
  714.       return;
  715.    file = window->file_info;
  716.    max_col = window->end_col + 1 - window->start_col;
  717.    line = window->cline;
  718.    normal = g_display.text_color;
  719.    block = g_display.block_color;
  720.    show_eol = mode.show_eol;
  721.  
  722.    /*
  723.     * set the screen pointer to physical screen memory.
  724.     */
  725.    screen_ptr = g_display.display_address;
  726.          /* 160 = 80 chars + 80 attr  for each line */
  727.    off = line * 160 + window->start_col * 2;
  728.  
  729.    /*
  730.     * figure which line to display.
  731.     * actually, we could be displaying any line in any file.  we display
  732.     *   the line_buffer only if window->cursor == g_status.buff_line
  733.     *   and window->cursor has been copied to g_status.line_buff.
  734.     */
  735.    text = cpf( window->cursor );
  736.    if (g_status.copied && ptoul( text ) == ptoul( g_status.buff_line ))
  737.       text = g_status.line_buff;
  738.    if (mode.inflate_tabs)
  739.       text = tabout( text );
  740.  
  741.    /*
  742.     * lets look at the base column.  if the line to display is shorter
  743.     *   than the base column, then set text to eol and we can't see the
  744.     *   eol either.
  745.     */
  746.    bc = window->bcol;
  747.    if (bc > 0) {
  748.       if ((col = linelen( text )) < bc) {
  749.          bc = col;
  750.          show_eol = FALSE;
  751.       }
  752.       text += bc;
  753.    }
  754.    bcol = window->bcol;
  755.    rline = window->rline;
  756.    if (file->block_type && rline >= file->block_br && rline <= file->block_er)
  757.       block_line = TRUE;
  758.    else
  759.       block_line = FALSE;
  760.  
  761.    /*
  762.     * do this if 1) a box block is marked, or 2) a stream block begins
  763.     *   and ends on the same line.
  764.     */
  765.    if (block_line == TRUE && (file->block_type == BOX ||
  766.          (file->block_type == STREAM &&
  767.          rline == file->block_br && rline == file->block_er))) {
  768.       len = linelen( text );
  769.  
  770.       /*
  771.        * start with the bc and ec equal to physical block marker.
  772.        */
  773.       bc = file->block_bc;
  774.       ec = file->block_ec;
  775.       if (ec < bcol || bc >= bcol + max_col)
  776.          /*
  777.           * we can't see block if ending column is less than the base col or
  778.           *   the beginning column is greater than max_col.
  779.           */
  780.          ec = bc = max_col + 1;
  781.       else if (ec < bcol + max_col) {
  782.          /*
  783.           * if the ec is less than the max column, make ec relative to
  784.           *   base column then figure the bc.
  785.           */
  786.          ec = ec - bcol;
  787.          if (bc < bcol)
  788.             bc = 0;
  789.          else
  790.             bc = bc - bcol;
  791.       } else if (bc < bcol + max_col) {
  792.          /*
  793.           * if the bc is less than the max column, make bc relative to
  794.           *   base column then figure the ec.
  795.           */
  796.          bc = bc - bcol;
  797.          if (ec > bcol + max_col)
  798.             ec = max_col;
  799.          else
  800.             ec = ec - bcol;
  801.       } else if (bc < bcol  &&  ec >= bcol + max_col) {
  802.          /*
  803.           * if the block is wider than the screen, make bc start at the
  804.           *   logical begin and make ec end at the logical end of the
  805.           *   window.
  806.           */
  807.          bc = 0;
  808.          ec = max_col;
  809.       }
  810.  
  811.  
  812.       _asm {
  813.         push    ds                      ; MUST save ds - push it on stack
  814.         push    si                      ; save si on stack
  815.         push    di                      ; save di on stack
  816.  
  817. ; on the stack so we can pop it when we're thru displaying line.
  818.         mov     ax, WORD PTR show_eol   ; get the show_eol flag
  819.         push    ax                      ; push the flag
  820.  
  821. ;
  822. ; set up local register variables
  823. ;
  824.         mov     ax, WORD PTR bc         ; get beginning column
  825.         mov     bl, al                  ; keep it in bl
  826.         mov     ax, WORD PTR ec         ; get ending column
  827.         mov     bh, al                  ; keep it in bh
  828.         mov     ax, WORD PTR normal     ; get normal attribute
  829.         mov     dl, al                  ; keep it in dl
  830.         mov     ax, WORD PTR block      ; get block attribute
  831.         mov     dh, al                  ; keep it in dh
  832.         mov     ax, WORD PTR max_col    ; get max number columns on screen
  833.         mov     ch, al                  ; keep it in ch
  834.         xor     cl, cl                  ; col = 0, keep col in cl
  835. ;
  836. ; load screen and text pointer
  837. ;
  838.         mov     di, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  839.         add     di, WORD PTR off                ; add offset of line
  840.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  841.         mov     es, ax
  842.         mov     si, WORD PTR text       ; load OFFSET of text ptr
  843.         mov     ax, WORD PTR text+2     ; load SEGMENT of text ptr
  844.         mov     ds, ax                  ; move segment of text in ds
  845.         cmp     si, 0                   ; is offset of text ptr == NULL?
  846.         jne     not_null                ; no, output string
  847.         cmp     ax, 0                   ; is segment of text ptr == NULL?
  848.         je      block_eol               ; yes, clear end of line
  849. not_null:
  850.         ALIGN   2
  851. top:
  852.         cmp     cl, ch          ; is col == max_col 0?
  853.         je      getout          ; yes, thru with line
  854.         lodsb                   ; get next char in string
  855.         cmp     al, CONTROL_Z   ; is it ^Z?
  856.         je      block_eol       ; yes, must check block past ^Z
  857.         cmp     al, '\n'        ; is it '\n'?
  858.         je      dspl_eol        ; yes, must check block past '\n'
  859.         mov     ah, dl          ; assume normal attribute
  860.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  861.         jl      ch_out1         ; yes, show char and normal attribute
  862.         cmp     cl, bh          ; is col > ec? (greater than ending col)
  863.         jg      ch_out1         ; yes, show char and normal attribute
  864.         mov     ah, dh          ; must be in a block - show block attribute
  865. ch_out1:
  866.         stosw                   ; else show char on screen
  867.         inc     cl              ; ++col
  868.         jmp     SHORT top       ; get another character
  869.         ALIGN   2
  870. dspl_eol:
  871.         pop     ax              ; look at the show_eol flag
  872.         push    ax              ; push it back on stack
  873.         or      ax, ax          ; or the flag - test for 0
  874.         je      block_eol       ; show_eol flag is FALSE, blank line
  875.         mov     al, EOL_CHAR    ; load some eol indicator
  876.         mov     ah, dl          ; assume normal attribute
  877.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  878.         jl      ch_out2         ; yes, show char and normal attribute
  879.         cmp     cl, bh          ; is col > ec? (greater than ending col)
  880.         jg      ch_out2         ; yes, show char and normal attribute
  881.         mov     ah, dh          ; must be in a block - show block attribute
  882.         ALIGN   2
  883. ch_out2:
  884.         stosw                   ; write eol and attribute to screen
  885.         inc     cl              ; ++col
  886.         cmp     cl, ch          ; is col == max_col?
  887.         je      getout          ; yes, we're done
  888.         ALIGN   2
  889. block_eol:
  890.         mov     al, ' '         ; clear rest of line w/ spaces
  891. b1:
  892.         mov     ah, dl          ; assume normal attribute
  893.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  894.         jl      ch_out3         ; yes, show char and normal attribute
  895.         cmp     cl, bh          ; is col > ec? (greater than ending col)
  896.         jg      ch_out3         ; yes, show char and normal attribute
  897.         mov     ah, dh          ; must be in a block - show block attribute
  898.         ALIGN   2
  899. ch_out3:
  900.         stosw                   ; write blank and attribute to screen
  901.         inc     cl              ; ++col
  902.         cmp     cl, ch          ; is col == max_col?
  903.         jl      b1              ; while less output block
  904.         ALIGN   2
  905. getout:
  906.         add     sp, 2           ; "pop" the show_eol flag
  907.         pop     di
  908.         pop     si
  909.         pop     ds
  910.       }
  911. /*
  912.       for (col=0; col < max_col; col++) {
  913.          attr = normal;
  914.          if (col >= bc && col <= ec)
  915.             attr = block;
  916.          if (col < len)
  917.             c = text[col];
  918.          else
  919.             c = ' ';
  920.          update_char( c, col, line, attr );
  921.       }
  922. */
  923.    } else if (block_line == TRUE && file->block_type == STREAM &&
  924.               (rline == file->block_br || rline == file->block_er)) {
  925.       len = linelen( text );
  926.       if (rline == file->block_br)
  927.          bc = file->block_bc;
  928.       else {
  929.          bc = file->block_ec + 1;
  930.          ec = normal;
  931.          normal = block;
  932.          block = ec;
  933.       }
  934.       if (bc < bcol)
  935.          bc = 0;
  936.       else if (bc < bcol + max_col)
  937.          bc = bc - bcol;
  938.       else
  939.          bc = max_col + 1;
  940.  
  941.       _asm {
  942.         push    ds                      ; MUST save ds - push it on stack
  943.         push    si                      ; save si on stack
  944.         push    di                      ; save di on stack
  945.  
  946. ; on the stack so we can pop it when we're thru displaying line.
  947.         mov     ax, WORD PTR show_eol   ; get the show_eol flag
  948.         push    ax                      ; push the flag
  949. ;
  950. ; set up local register variables
  951. ;
  952.         mov     ax, WORD PTR bc         ; get beginning column
  953.         mov     bl, al                  ; keep it in bl
  954.         mov     ax, WORD PTR normal     ; get normal attribute
  955.         mov     dl, al                  ; keep it in dl
  956.         mov     ax, WORD PTR block      ; get block attribute
  957.         mov     dh, al                  ; keep it in dh
  958.         mov     ax, WORD PTR max_col    ; get max number columns on screen
  959.         mov     ch, al                  ; keep it in ch
  960.         xor     cl, cl                  ; col = 0, keep col in cl
  961. ;
  962. ; load screen and text pointer
  963. ;
  964.         mov     di, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  965.         add     di, WORD PTR off                ; add offset of line
  966.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  967.         mov     es, ax
  968.         mov     si, WORD PTR text       ; load OFFSET of text ptr
  969.         mov     ax, WORD PTR text+2     ; load SEGMENT of text ptr
  970.         mov     ds, ax                  ; move segment of text in ds
  971.         cmp     si, 0                   ; is offset of text ptr == NULL?
  972.         jne     nott_null               ; no, output string
  973.         cmp     ax, 0                   ; is segment of text ptr == NULL?
  974.         je      stream_eol              ; yes, clear end of line
  975. nott_null:
  976.         ALIGN   2
  977. ttop:
  978.         cmp     cl, ch          ; is col == max_col?
  979.         je      ggetout         ; yes, thru with line
  980.         lodsb                   ; get next char in string
  981.         cmp     al, CONTROL_Z   ; is it ^Z?
  982.         je      stream_eol      ; yes, must check block past ^Z
  983.         cmp     al, '\n'        ; is it '\n'?
  984.         je      ddspl_eol       ; yes, must check block past '\n'
  985.         mov     ah, dl          ; assume normal attribute
  986.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  987.         jl      str_out1        ; yes, show char and normal attribute
  988.         mov     ah, dh          ; must be in a block - show block attribute
  989.         ALIGN   2
  990. str_out1:
  991.         stosw                   ; else show char on screen
  992.         inc     cl              ; ++col
  993.         jmp     SHORT ttop      ; get another character
  994.         ALIGN   2
  995.  
  996. ddspl_eol:
  997.         pop     ax              ; look at the show_eol flag
  998.         push    ax              ; push it back on stack
  999.         or      ax, ax          ; or the flag - test for 0
  1000.         je      stream_eol      ; show_eol flag is FALSE, blank line
  1001.         mov     al, EOL_CHAR    ; load some eol indicator
  1002.         mov     ah, dl          ; assume normal attribute
  1003.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  1004.         jl      str_out2        ; yes, show char and normal attribute
  1005.         mov     ah, dh          ; must be in a block - show block attribute
  1006.         ALIGN   2
  1007. str_out2:
  1008.         stosw                   ; write blank and attribute to screen
  1009.         inc     cl              ; ++col
  1010.         cmp     cl, ch          ; is col == max_col?
  1011.         je      ggetout         ; yes, we're done
  1012.         ALIGN   2
  1013.  
  1014. stream_eol:
  1015.         mov     al, ' '         ; clear rest of line w/ spaces
  1016.         ALIGN   2
  1017. c1:
  1018.         mov     ah, dl          ; assume normal attribute
  1019.         cmp     cl, bl          ; is col < bc? (less than beginning col)
  1020.         jl      str_out3        ; yes, show char and normal attribute
  1021.         mov     ah, dh          ; must be in a block - show block attribute
  1022.         ALIGN   2
  1023. str_out3:
  1024.         stosw                   ; write blank and attribute to screen
  1025.         inc     cl              ; ++col
  1026.         cmp     cl, ch          ; is col == max_col?
  1027.         jl      c1              ; while less output block
  1028.         ALIGN   2
  1029. ggetout:
  1030.         add     sp, 2           ; "pop" show_eol
  1031.         pop     di
  1032.         pop     si
  1033.         pop     ds
  1034.       }
  1035. /*
  1036.       for (col=0; col < max_col; col++) {
  1037.          attr = normal;
  1038.          if (col >= bc && col <= ec)
  1039.             attr = block;
  1040.          if (col < len)
  1041.             c = text[col];
  1042.          else
  1043.             c = ' ';
  1044.          update_char( c, col, line, attr );
  1045.       }
  1046. */
  1047.    } else {
  1048.       if (block_line)
  1049.          attr = block;
  1050.       else
  1051.          attr = normal;
  1052.       _asm {
  1053.         mov     dx, ds          ; MUST save ds - keep it in dx
  1054.         push    di              ; save di on stack
  1055.         push    si              ; save si on stack
  1056.  
  1057. ; on the stack so we can pop it when we're thru displaying line.
  1058.         mov     ax, WORD PTR show_eol   ; get the show_eol flag
  1059.         push    ax                      ; push the flag
  1060.  
  1061.         mov     bx, WORD PTR attr               ; keep attribute in bl
  1062.         mov     bh, '\n'                        ; keep '\n' in bh
  1063.         mov     cx, WORD PTR max_col            ; keep max_col in cx
  1064.         mov     di, WORD PTR screen_ptr         ; load OFFST of screen ptr
  1065.         add     di, WORD PTR off                ; add offset of line
  1066.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  1067.         mov     es, ax
  1068.         mov     si, WORD PTR text       ; load OFFSET of text ptr
  1069.         mov     ax, WORD PTR text+2     ; load SEGMENT of text ptr
  1070.         mov     ds, ax                  ; move segment of text in ds
  1071.         cmp     si, 0                   ; is offset of pointer == NULL?
  1072.         jne     nnot_null               ; no, output string
  1073.         cmp     ax, 0                   ; is segment of pointer == NULL?
  1074.         je      clreol                  ; yes, then clear rest of line
  1075. nnot_null:
  1076.         mov     ah, bl                  ; get attribute
  1077.         ALIGN   2
  1078. topp:
  1079.         or      cx, cx          ; col == 0 ?
  1080.         je      getoutt         ; yes, thru with line
  1081.         lodsb                   ; get next char in string
  1082.         cmp     al, CONTROL_Z   ; is it ^Z
  1083.         je      clreol          ; yes, clear end of line
  1084.         cmp     al, bh          ; is it '\n'
  1085.         je      normeol          ; yes, clear end of line
  1086.         stosw                   ; else show char on screen
  1087.         dec     cx              ; --col, count down from max_column
  1088.         jmp     SHORT topp      ; get another character
  1089.         ALIGN   2
  1090.  
  1091. normeol:
  1092.         pop     ax              ; look at the show_eol flag
  1093.         push    ax              ; push it back on stack
  1094.         or      ax, ax          ; or the flag - test for 0
  1095.         je      clreol          ; show_eol flag is FALSE, blank line
  1096.         mov     al, EOL_CHAR    ; load some eol indicator
  1097.         mov     ah, bl          ; assume normal attribute
  1098.         stosw                   ; write blank and attribute to screen
  1099.         dec     cl              ; ++col
  1100.         or      cl, cl          ; is col == 0?
  1101.         je      getoutt         ; yes, we're done
  1102.         ALIGN   2
  1103.  
  1104. clreol:
  1105.         mov     ah, bl          ; get attribute
  1106.         mov     al, ' '         ; clear eol with ' '
  1107.         rep     stosw           ; count is in cx - set rest of line to ' '
  1108.         ALIGN   2
  1109. getoutt:
  1110.         add     sp, 2           ; "pop" show_eol
  1111.         pop     si
  1112.         pop     di
  1113.         mov     ds, dx
  1114.       }
  1115.    }
  1116. /*
  1117.    if (orig != NULL) {
  1118.       text = orig;
  1119.       screen_ptr = g_display.display_address + line * 160 + col * 2;
  1120.       for (; *text != '\n' && *text != ^Z && col < max_col; text++, col++) {
  1121.          *screen_ptr++ = *text;
  1122.          *screen_ptr++ = attr;
  1123.       }
  1124.    }
  1125.    if (col < max_col)
  1126.       eol_clear( col, line, attr );
  1127. */
  1128. }
  1129.  
  1130.  
  1131. /*
  1132.  * Name:    tabout
  1133.  * Purpose: Expand tabs in display line
  1134.  * Date:    October 31, 1992
  1135.  * Passed:  s:  string pointer
  1136.  * Notes:   Expand tabs in the display line according to current tab.
  1137.  *          If eol display is on, let's display tabs, too.
  1138.  */
  1139. text_ptr tabout( text_ptr s )
  1140. {
  1141. text_ptr to;
  1142. int space;
  1143. int col;
  1144. int tab_size;
  1145. int show_tab;
  1146.  
  1147.    tab_size = mode.ptab_size;
  1148.    show_tab = mode.show_eol;
  1149.    to = g_status.tabout_buff;
  1150.    s = cpf( s );
  1151.    _asm {
  1152.         push    si
  1153.         push    di
  1154.         push    ds
  1155.         push    es
  1156.         push    bp      ; use bp for show_tab flag -  we can't use it anyway
  1157.  
  1158.         cld                             ; clear direction flag - go up
  1159.         mov     dx, WORD PTR show_tab   ; temporarily hold show_tab in dx
  1160.         mov     bx, WORD PTR tab_size   ; keep tab_size in bx
  1161.         xor     cx, cx                  ; keep col in cx
  1162.  
  1163.         mov     di, WORD PTR to
  1164.         mov     ax, WORD PTR to+2
  1165.         mov     es, ax                  ; es:di == to or the destination
  1166.         mov     si, WORD PTR s
  1167.         mov     ax, WORD PTR s+2
  1168.         mov     ds, ax                  ; ds:si == s or the source
  1169.         mov     bp, dx                  ; now put show_tab in bp
  1170.                                         ; we will not access any
  1171.                                         ; local variables from now on
  1172.         ALIGN   2
  1173. top:
  1174.         lodsb                           ; al == BYTE PTR ds:si
  1175.         cmp     al, CONTROL_Z           ; are we at end of string
  1176.         je      get_out
  1177.         cmp     cx, MAX_LINE_LENGTH     ; are at end of tabout buffer?
  1178.         jge     get_out
  1179.  
  1180.         cmp     al, '\t'                ; is this a tab character?
  1181.         je      expand_tab
  1182.  
  1183.         stosb                           ; store character in es:di inc di
  1184.         inc     cx                      ; increment col counter
  1185.         cmp     al, '\n'                ; was that byte a new line?
  1186.         je      get_out
  1187.         jmp     SHORT top
  1188.         ALIGN   2
  1189.  
  1190. expand_tab:
  1191.         mov     ax, cx
  1192.         xor     dx, dx                  ; set up dx:ax for IDIV
  1193.         IDIV    bx                      ; col % tab_size
  1194.         mov     ax, bx                  ; put tab_size in bx
  1195.         sub     ax, dx                  ; ax = tab_size - (col % tab_size)
  1196.         mov     dx, ax                  ; put ax in dx
  1197.         add     cx, ax                  ; col += space
  1198.         cmp     cx, MAX_LINE_LENGTH     ; is col > MAX_LINE_LENGTH?
  1199.         je      get_out                 ; yes, get out
  1200.         cmp     bp, 0                   ; was show_tab flag set?
  1201.         je      no_show_tab
  1202.         mov     ax, '\t'                ; put tab character in ax
  1203.         stosb                           ; store in es:di and incr di
  1204.         dec     dx
  1205.         ALIGN   2
  1206.  
  1207. no_show_tab:
  1208.          mov    ax, ' '                 ; save blank character in ax
  1209.          ALIGN  2
  1210.  
  1211. space_fill:
  1212.          cmp    dx, 0                   ; any spaces left to fill?
  1213.          je     top                     ; no, get another character
  1214.          stosb                          ; store ' ' in es:di and incr di
  1215.          dec    dx                      ; space--
  1216.          jmp    SHORT space_fill        ; fill space
  1217.          ALIGN  2
  1218.  
  1219. get_out:
  1220.         mov     es:[di], CONTROL_Z
  1221.  
  1222.         pop     bp
  1223.         pop     es
  1224.         pop     ds
  1225.         pop     di
  1226.         pop     si
  1227.    }
  1228.    return( g_status.tabout_buff );
  1229.  
  1230. /*
  1231.    tab_size = mode.tab_size;
  1232.    show_tab = mode.show_eol;
  1233.    to = g_status.tabout_buff;
  1234.    s = cpf( s );
  1235.    for (col=0; *s != CONTROL_Z && col < (MAX_LINE_LENGTH - (tab_size +1));
  1236.                                                                       s++) {
  1237.       if (*s != '\t') {
  1238.          *to++ = *s;
  1239.          ++col;
  1240.          if (*s == '\n')
  1241.             break;
  1242.       } else {
  1243.          space = tab_size - (col % tab_size);
  1244.          col += space;
  1245.          if (show_tab) {
  1246.             *to++ = '\t';
  1247.             space--;
  1248.          }
  1249.          for (; space > 0; space--)
  1250.             *to++ = ' ';
  1251.       }
  1252.    }
  1253.    *to = CONTROL_Z;
  1254.    return( g_status.tabout_buff );
  1255. */
  1256. }
  1257.  
  1258.  
  1259.  
  1260. /*
  1261.  * Name:    c_output
  1262.  * Purpose: Output one character on prompt lines
  1263.  * Date:    June 5, 1991
  1264.  * Passed:  c:     character to output to screen
  1265.  *          col:   col to display character
  1266.  *          line:  line number to display character
  1267.  *          attr:  attribute of character
  1268.  * Returns: none
  1269.  */
  1270. void c_output( int c, int col, int line, int attr )
  1271. {
  1272. void far *screen_ptr;
  1273. int off;
  1274.  
  1275.    screen_ptr = (void far *)g_display.display_address;
  1276.    off = line * 160 + col * 2;
  1277.  
  1278.    _asm {
  1279.         mov     bx, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  1280.         add     bx, WORD PTR off                ; add offset of line:col
  1281.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  1282.         mov     es, ax
  1283.         mov     cx, WORD PTR attr       ; get attribute
  1284.         mov     ah, cl                  ; put in ah
  1285.         mov     cx, WORD PTR c          ; get character
  1286.         mov     al, cl                  ; put in al
  1287.         mov     WORD PTR es:[bx], ax    ; show char on screen
  1288.    }
  1289.  
  1290. /*
  1291.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1292.    *screen_ptr++ = c;
  1293.    *screen_ptr = attr;
  1294. */
  1295. }
  1296.  
  1297.  
  1298. /*
  1299.  * Name:    s_output
  1300.  * Purpose: To output a string
  1301.  * Date:    June 5, 1991
  1302.  * Passed:  s:     string to output
  1303.  *          line:  line to display
  1304.  *          col:   column to begin display
  1305.  *          attr:  color to display string
  1306.  * Notes:   This function is used to output most strings not part of file text.
  1307.  *
  1308.  *          All strings in the SMALL memory model are in the default NEAR data
  1309.  *          segment (used in production version of tde).  Prototype the output
  1310.  *          string as far because when compiling for debugging, you must
  1311.  *          compile with the LARGE library since the /Zi code will not
  1312.  *          fit in the SMALL model.
  1313.  */
  1314. void s_output( char far *s, int line, int col, int attr )
  1315. {
  1316. void far *screen_ptr;
  1317. int off;
  1318. int max_col;
  1319.  
  1320.    max_col = g_display.ncols;
  1321.    screen_ptr = (void far *)g_display.display_address;
  1322.    off = line * 160 + col * 2;
  1323.  
  1324.    _asm {
  1325.         push    ds              ; save ds on stack
  1326.         push    di              ; save di on stack
  1327.         push    si              ; save si on stack
  1328.  
  1329.         mov     bx, WORD PTR attr               ; keep attribute in bx
  1330.         mov     cx, WORD PTR col                ; put cols in cx
  1331.         mov     dx, WORD PTR max_col            ; keep max_col in dx
  1332.         mov     di, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  1333.         add     di, WORD PTR off                ; add offset of line:col
  1334.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  1335.         mov     es, ax
  1336.         mov     si, WORD PTR s  ; load offset of string ptr
  1337.         or      si, si          ; is it == NULL?
  1338.         je      getout          ; yes, no output needed
  1339.         mov     ax, WORD PTR s+2        ; load segment of string ptr
  1340.         or      ax, ax          ; is pointer == NULL?
  1341.         je      getout          ; yes, no output needed
  1342.         mov     ds, ax          ; load segment of text in ds
  1343.         mov     ah, bl          ; put attribute in AH
  1344.         ALIGN   2
  1345. top:
  1346.         cmp     cx, dx          ; col < max_cols?
  1347.         jge     getout          ; no, thru with line
  1348.         lodsb                   ; get next char in string - put in al
  1349.         or      al, al          ; is it '\0'
  1350.         je      getout          ; yes, end of string
  1351.         cmp     al, '\n'        ; is it '\n'?
  1352.         je      getout          ; yes, end of string
  1353.         stosw                   ; else show attr + char on screen (ah + al)
  1354.         inc     cx              ; col++
  1355.         jmp     SHORT top       ; get another character
  1356.         ALIGN   2
  1357. getout:
  1358.         pop     si              ; get back si
  1359.         pop     di              ; get back di
  1360.         pop     ds              ; get back ds
  1361.    }
  1362.  
  1363. /*
  1364.    screen_ptr = g_display.display_address + line * 160 + col * 2;
  1365.    max_col = g_display.ncols;
  1366.    while (*s && col < max) {
  1367.       *screen_ptr++ = *s++;
  1368.       *screen_ptr++ = attr;
  1369.    }
  1370. */
  1371. }
  1372.  
  1373.  
  1374. /*
  1375.  * Name:    eol_clear
  1376.  * Purpose: To clear the line from col to max columns
  1377.  * Date:    June 5, 1991
  1378.  * Passed:  col:   column to begin clear
  1379.  *          line:  line to clear
  1380.  *          attr:  color to clear
  1381.  * Notes:   Basic assembly
  1382.  */
  1383. void eol_clear( int col, int line, int attr )
  1384. {
  1385. int max_col;
  1386. void far *screen_ptr;
  1387. int off;
  1388.  
  1389.    max_col = g_display.ncols;
  1390.    screen_ptr = (void far *)g_display.display_address;
  1391.    off = line * 160 + col * 2;
  1392.  
  1393.    _asm {
  1394.         push    di                              ; save di on stack
  1395.  
  1396.         mov     bx, WORD PTR attr               ; keep attribute in bx
  1397.         mov     dx, WORD PTR col                ; put cols in dx
  1398.         mov     cx, WORD PTR max_col            ; put max_col in cx
  1399.         cmp     dx, cx                          ; max_cols < cols?
  1400.         jge     getout                          ; no, thru with line
  1401.         sub     cx, dx                          ; number of column to clear
  1402.         mov     di, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  1403.         add     di, WORD PTR off                ; add offset of line:col
  1404.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  1405.         mov     es, ax
  1406.         mov     ah, bl                          ; get attribute in ah
  1407.         mov     al, ' '                         ; store ' ' in al
  1408.         rep     stosw                           ; clear to end of line
  1409. getout:
  1410.         pop     di                              ; get back di from stack
  1411.    }
  1412.  
  1413. /*
  1414.    for (; col < g_display.ncols; col++) {
  1415.       *p++ = ' ';
  1416.       *p++ = attr;
  1417.    }
  1418. */
  1419. }
  1420.  
  1421.  
  1422. /*
  1423.  * Name:    window_eol_clear
  1424.  * Purpose: To clear the line from start_col to end_col
  1425.  * Date:    June 5, 1991
  1426.  * Passed:  col:   column to begin clear
  1427.  *          line:  line to clear
  1428.  *          attr:  color to clear
  1429.  * Notes:   Basic assembly
  1430.  */
  1431. void window_eol_clear( WINDOW *window, int attr )
  1432. {
  1433. int max_col;
  1434. void far *screen_ptr;
  1435. int off;
  1436.  
  1437.    screen_ptr = (void far *)g_display.display_address;
  1438.    off = window->cline * 160 + window->start_col * 2;
  1439.    max_col = window->end_col + 1 - window->start_col;
  1440.  
  1441.    _asm {
  1442.         push    di                              ; save di on stack
  1443.  
  1444.         mov     bx, WORD PTR attr               ; keep attribute in bx
  1445.         mov     cx, WORD PTR max_col            ; put max_col in cx
  1446.         mov     di, WORD PTR screen_ptr         ; load OFFSET of screen ptr
  1447.         add     di, WORD PTR off                ; add offset of line:col
  1448.         mov     ax, WORD PTR screen_ptr+2       ; load SEGMENT of screen ptr
  1449.         mov     es, ax
  1450.         mov     ah, bl                          ; get attribute in ah
  1451.         mov     al, ' '                         ; store ' ' in al
  1452.         rep     stosw                           ; clear to end of line
  1453. getout:
  1454.         pop     di                              ; get back di from stack
  1455.    }
  1456.  
  1457. /*
  1458.    for (; col < g_display.ncols; col++) {
  1459.       *p++ = ' ';
  1460.       *p++ = attr;
  1461.    }
  1462. */
  1463. }
  1464.  
  1465.  
  1466. /*
  1467.  * Name:    upper_asm
  1468.  * Purpose: To convert all lower case characters to upper characters
  1469.  * Date:    June 5, 1991
  1470.  * Passed:  s:    the starting point
  1471.  *          count: number of characters to convert (unsigned)
  1472.  * Returns: none
  1473.  * Notes:   This function goes faster if machine works with WORDs.  See if
  1474.  *           first BYTE in string is WORD aligned.  If it is not, get first
  1475.  *           BYTE in string then the rest of string is WORD aligned.
  1476.  *
  1477.  *          The pointer should have been normalized, using the nptos, as
  1478.  *          this function does not handle segment wrap.
  1479.  *
  1480.  *          ax, ah, al  = characters from string
  1481.  *          bl          = 'a'
  1482.  *          bh          = 'z'
  1483.  *          cx          = number of characters to look at
  1484.  *          dl          = 0x20, xor 0x20 with lower case to get upper case
  1485.  *          ds:si       = far pointer to character string
  1486.  *                        use ds:si so there is no segment override
  1487.  */
  1488. void upper_asm( text_ptr s, unsigned count )
  1489. {
  1490.    _asm {
  1491.         push    ds              ; save ds on stack
  1492.         push    si              ; save si on stack
  1493.  
  1494.         mov     cx, WORD PTR count      ; load count in cx
  1495.         jcxz    get_out                 ; 1st, if count == 0 then do nothing
  1496.         mov     si, WORD PTR s          ; load OFFSET of s
  1497.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  1498.         mov     ds, ax
  1499.         or      si, si          ; is offset of string == NULL or 0?
  1500.         jne     not_null        ; no, do string stuff
  1501.         or      ax, ax          ; is segment of string == NULL or 0?
  1502.         je      get_out         ; yes, don't upper case a NULL string
  1503.         ALIGN   2
  1504. not_null:
  1505.         mov     bh, 'z'         ; keep 'z' in bh
  1506.         mov     bl, 'a'         ; keep 'a' in bl
  1507.         mov     dl, 0x20        ; keep 0x20 in dl
  1508.         mov     ax, si          ; move offset of si to ax
  1509.         shr     ax, 1           ; shift right into carry flag
  1510.         jnc     top             ; is string WORD aligned?
  1511.         mov     al, BYTE PTR [si]       ; no, get a BYTE
  1512.         cmp     al, bl          ; is al < 'a' (use unsigned test)
  1513.         jb      word_align      ; yes, dec count and align on WORD
  1514.         cmp     al, bh          ; is al > 'z' (use unsigned test)
  1515.         ja      word_align      ; yes, dec count and align on WORD
  1516.         xor     al, dl          ; convert lower case to upper
  1517.         mov     BYTE PTR [si], al       ; store the character or BYTE
  1518.         ALIGN   2
  1519. word_align:
  1520.         inc     si              ; inc the string pointer - now WORD aligned
  1521.         dec     cx              ; decrement the character count
  1522.         jcxz    get_out         ; if count or cx == 0 then we're done, get_out
  1523.         ALIGN   2
  1524. top:
  1525.         mov     ax, WORD PTR [si]       ; string is WORD aligned, get two BYTEs
  1526.         cmp     al, bl          ; is al < 'a'?
  1527.         jb      upper_hi        ; yes, dec count and check the hi byte
  1528.         cmp     al, bh          ; is al > 'z'?
  1529.         ja      upper_hi        ; yes, dec count and check the hi byte
  1530.         xor     al, dl          ; convert lower case to upper
  1531.         ALIGN   2
  1532. upper_hi:
  1533.         dec     cx              ; decrement the count
  1534.         jcxz    clean_up        ; if count or cx == 0 then we're done, clean_up
  1535.         cmp     ah, bl          ; is al < 'a'?
  1536.         jb      save_word       ; yes, dec count and do next word
  1537.         cmp     ah, bh          ; is al > 'z'?
  1538.         ja      save_word       ; yes, dec count and do next word
  1539.         xor     ah, dl          ; convert lower case to upper
  1540.         ALIGN   2
  1541. save_word:
  1542.         mov     WORD PTR [si], ax       ; else, save changes
  1543.         dec     cx              ; decrement the count
  1544.         jcxz    get_out         ; if count or cx == 0 then we're done, get_out
  1545.         inc     si              ; increment the pointer to next word
  1546.         inc     si
  1547.         jmp     SHORT top       ; look at next WORD
  1548.         ALIGN   2
  1549. clean_up:
  1550.         mov     WORD PTR [si], ax       ; else, save changes then we're done
  1551.         ALIGN   2
  1552. get_out:
  1553.         pop     si              ; get back si from stack
  1554.         pop     ds              ; get back ds from stack
  1555.    }
  1556. /*
  1557.    while (count-- > 0) {
  1558.       if (*s >= 'a' && *s <= 'z')
  1559.          *s++ &= 0xdf;
  1560.    }
  1561. */
  1562. }
  1563.  
  1564.  
  1565. /*
  1566.  * Name:    lower_asm
  1567.  * Purpose: To convert all upper case characters to lower characters
  1568.  * Date:    June 5, 1991
  1569.  * Passed:  s:    the starting point
  1570.  *          count: number of characters to convert (unsigned)
  1571.  * Returns: none
  1572.  * Notes:   This function goes faster if machine works with WORDs.  See if
  1573.  *           first BYTE in string is WORD aligned.  If it is not, get first
  1574.  *           BYTE in string then the rest of string is WORD aligned.
  1575.  *
  1576.  *          The pointer should have been normalized, using the nptos, as
  1577.  *          this function does not handle segment wrap.  One could safely
  1578.  *          pass a count of 0xFFF0 if the pointer has been normalized to
  1579.  *          a segment
  1580.  *
  1581.  *          ax, ah, al  = characters from string
  1582.  *          bl          = 'A'
  1583.  *          bh          = 'Z'
  1584.  *          cx          = number of characters to look at, unsigned
  1585.  *          dl          = 0x20, or upper case with 0x20 to get lower case
  1586.  *          ds:si       = far pointer to character string
  1587.  *                        use ds:si so there is no segment override
  1588.  */
  1589. void lower_asm( text_ptr s, unsigned count )
  1590. {
  1591.    _asm {
  1592.         push    ds              ; save ds on stack
  1593.         push    si              ; save si on stack
  1594.  
  1595.         mov     cx, WORD PTR count      ; load count in cx
  1596.         jcxz    get_out                 ; 1st, if count == 0 then do nothing
  1597.         mov     si, WORD PTR s          ; load OFFSET of s
  1598.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  1599.         mov     ds, ax
  1600.         or      si, si          ; is offset of string == NULL or 0?
  1601.         jne     not_null        ; no, do string stuff
  1602.         or      ax, ax          ; is segment of string == NULL or 0?
  1603.         je      get_out         ; yes, don't upper case a NULL string
  1604.         ALIGN   2
  1605. not_null:
  1606.         mov     bh, 'Z'         ; keep 'z' in bh
  1607.         mov     bl, 'A'         ; keep 'a' in bl
  1608.         mov     dl, 0x20        ; keep 0x20 in dl
  1609.         mov     ax, si          ; move offset of si to ax
  1610.         shr     ax, 1           ; shift right into carry flag
  1611.         jnc     top             ; is string WORD aligned?
  1612.         mov     al, BYTE PTR [si]       ; no, get a BYTE
  1613.         cmp     al, bl          ; is al < 'A' (use unsigned test)
  1614.         jb      word_align      ; yes, dec count and align on WORD
  1615.         cmp     al, bh          ; is al > 'Z' (use unsigned test)
  1616.         ja      word_align      ; yes, dec count and align on WORD
  1617.         or      al, dl          ; convert upper case to lower
  1618.         mov     BYTE PTR [si], al       ; store the character or BYTE
  1619.         ALIGN   2
  1620. word_align:
  1621.         inc     si              ; inc the string pointer - now WORD aligned
  1622.         dec     cx              ; decrement the character count
  1623.         jcxz    get_out         ; if count or cx == 0 then we're done
  1624.         ALIGN   2
  1625. top:
  1626.         mov     ax, WORD PTR [si]       ; string is WORD aligned, get two BYTEs
  1627.         cmp     al, bl          ; is al < 'A'?
  1628.         jb      lower_hi        ; yes, dec count and check the hi byte
  1629.         cmp     al, bh          ; is al > 'Z'?
  1630.         ja      lower_hi        ; yes, dec count and check the hi byte
  1631.         or      al, dl          ; convert upper case to lower
  1632.         ALIGN   2
  1633. lower_hi:
  1634.         dec     cx              ; decrement the character count
  1635.         jcxz    clean_up        ; if count or cx == 0 then we're done, clean_up
  1636.         cmp     ah, bl          ; is al < 'A'?
  1637.         jb      save_word       ; yes, dec count and do next word
  1638.         cmp     ah, bh          ; is al > 'Z'?
  1639.         ja      save_word       ; yes, dec count and do next word
  1640.         or      ah, dl          ; convert upper case to lower
  1641.         ALIGN   2
  1642. save_word:
  1643.         mov     WORD PTR [si], ax       ; else, save changes
  1644.         dec     cx              ; decrement the count
  1645.         jcxz    get_out         ; if count or cx == 0 then we're done, get out
  1646.         inc     si              ; increment the pointer to next word
  1647.         inc     si
  1648.         jmp     SHORT top       ; look at next WORD
  1649.         ALIGN   2
  1650. clean_up:
  1651.         mov     WORD PTR [si], ax       ; else, save changes then we're done
  1652.         ALIGN   2
  1653. get_out:
  1654.         pop     si              ; get back si from stack
  1655.         pop     ds              ; get back ds from stack
  1656.    }
  1657. /*
  1658.    while (count-- > 0) {
  1659.       if (*s >= 'a' && *s <= 'z')
  1660.          *s++ &= 0xdf;
  1661.    }
  1662. */
  1663. }
  1664.  
  1665.  
  1666. /*
  1667.  * Name:    rot13_asm
  1668.  * Purpose: To rotate all alphabet characters by 13
  1669.  * Date:    June 5, 1991
  1670.  * Passed:  s:    the starting point
  1671.  *          count: number of characters to convert (unsigned)
  1672.  * Returns: none
  1673.  * Notes:   This function goes faster if machine works with WORDs.  See if
  1674.  *           first BYTE in string is WORD aligned.  If it is not, get first
  1675.  *           BYTE in string then the rest of string is WORD aligned.  Lets
  1676.  *           test for lower case letters first, since there are probably
  1677.  *           more of them.
  1678.  *
  1679.  *          The pointer should have been normalized, using the nptos, as
  1680.  *          this function does not handle segment wrap.  One could safely
  1681.  *          pass a count of 0xFFF0 if the pointer has been normalized to
  1682.  *          a segment.
  1683.  *
  1684.  *          ax, ah, al  = characters from string
  1685.  *          cx          = number of characters to look at, unsigned
  1686.  *          ds:si       = far pointer to character string
  1687.  *                        use ds:si so there is no segment override
  1688.  */
  1689. void rot13_asm( text_ptr s, unsigned count )
  1690. {
  1691.    _asm {
  1692.         push    ds              ; save ds on stack
  1693.         push    si              ; save si on stack
  1694.  
  1695.         mov     cx, WORD PTR count      ; load count in cx
  1696.         jcxz    goto_get_out            ; 1st, if count == 0 then do nothing
  1697.         mov     si, WORD PTR s          ; load OFFSET of s
  1698.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  1699.         mov     ds, ax
  1700.         or      si, si          ; is offset of string == NULL or 0?
  1701.         jne     not_null        ; no, do string stuff
  1702.         or      ax, ax          ; is segment of string == NULL or 0?
  1703.         je      goto_get_out    ; yes, don't upper case a NULL string
  1704.         ALIGN   2
  1705. not_null:
  1706.         mov     ax, si          ; move offset of si to ax
  1707.         shr     ax, 1           ; shift right into carry flag
  1708.         jnc     top             ; is string WORD aligned?
  1709.         mov     al, BYTE PTR [si]       ; no, get a BYTE
  1710.  
  1711.         cmp     al, 'z'         ; is al > 'z'
  1712.         ja      word_align      ; yes, dec count and align on WORD - not alpha
  1713.         cmp     al, 'm'         ; is al > 'm'
  1714.         ja      sub_13          ; yes, sub 13 from letter
  1715.         cmp     al, 'a'         ; is al >= 'a'?
  1716.         jae     add_13          ; yes, add 13 to letter
  1717.  
  1718.         cmp     al, 'Z'         ; is al > 'Z'
  1719.         ja      word_align      ; yes, dec count and align on WORD - not alpha
  1720.         cmp     al, 'M'         ; is al > 'M'
  1721.         ja      sub_13          ; yes, sub 13 from letter
  1722.         cmp     al, 'A'         ; is al >= 'A'?
  1723.         jae     add_13          ; yes, add 13 to letter
  1724.         jmp     SHORT word_align
  1725.         ALIGN   2
  1726. add_13:
  1727.         add     al, 13
  1728.         jmp     SHORT contin
  1729. goto_get_out:
  1730.         jmp     SHORT get_out
  1731. sub_13:
  1732.         sub     al, 13
  1733. contin:
  1734.         mov     BYTE PTR [si], al       ; store the character or BYTE
  1735.         ALIGN   2
  1736. word_align:
  1737.         inc     si              ; inc the string pointer - now WORD aligned
  1738.         dec     cx              ; decrement the character count
  1739.         jcxz    get_out         ; if count or cx == 0 then we're done
  1740.         ALIGN   2
  1741. top:
  1742.         mov     ax, WORD PTR [si]       ; string is WORD aligned, get two BYTEs
  1743.         cmp     al, 'z'         ; is al > 'z'
  1744.         ja      check_hi
  1745.         cmp     al, 'm'         ; is al > 'm'
  1746.         ja      lo_sub_13       ; yes, sub 13 from letter
  1747.         cmp     al, 'a'         ; is al >= 'a'?
  1748.         jae     lo_add_13       ; yes, add 13 to letter
  1749.  
  1750.         cmp     al, 'Z'         ; is al > 'Z'
  1751.         ja      check_hi
  1752.         cmp     al, 'M'         ; is al > 'M'
  1753.         ja      lo_sub_13       ; yes, sub 13 from letter
  1754.         cmp     al, 'A'         ; is al >= 'A'?
  1755.         jae     lo_add_13       ; yes, add 13 to letter
  1756.         jmp     SHORT check_hi
  1757.         ALIGN   2
  1758.  
  1759. lo_add_13:
  1760.         add     al, 13
  1761.         jmp     SHORT check_hi
  1762. lo_sub_13:
  1763.         sub     al, 13
  1764.         ALIGN   2
  1765. check_hi:
  1766.         dec     cx              ; decrement the character count
  1767.         jcxz    clean_up        ; if count or cx == 0 then we're done, clean_up
  1768.  
  1769.         cmp     ah, 'z'         ; is ah > 'z'
  1770.         ja      save_word
  1771.         cmp     ah, 'm'         ; is ah > 'm'
  1772.         ja      hi_sub_13       ; yes, sub 13 from letter
  1773.         cmp     ah, 'a'         ; is ah >= 'a'?
  1774.         jae     hi_add_13       ; yes, add 13 to letter
  1775.  
  1776.         cmp     ah, 'Z'         ; is ah > 'Z'
  1777.         ja      save_word
  1778.         cmp     ah, 'M'         ; is ah > 'M'
  1779.         ja      hi_sub_13       ; yes, sub 13 from letter
  1780.         cmp     ah, 'A'         ; is ah >= 'A'?
  1781.         jae     hi_add_13       ; yes, add 13 to letter
  1782.         jmp     SHORT save_word
  1783.         ALIGN   2
  1784.  
  1785. hi_add_13:
  1786.         add     ah, 13
  1787.         jmp     SHORT save_word
  1788. hi_sub_13:
  1789.         sub     ah, 13
  1790.         ALIGN   2
  1791.  
  1792. save_word:
  1793.         mov     WORD PTR [si], ax       ; else, save changes
  1794.         dec     cx              ; decrement the count
  1795.         jcxz    get_out         ; if count or cx == 0 then we're done, get out
  1796.         inc     si              ; increment the pointer to next word
  1797.         inc     si
  1798.         jmp     SHORT top       ; look at next WORD
  1799.         ALIGN   2
  1800. clean_up:
  1801.         mov     WORD PTR [si], ax       ; else, save changes then we're done
  1802.         ALIGN   2
  1803. get_out:
  1804.         pop     si              ; get back si from stack
  1805.         pop     ds              ; get back ds from stack
  1806.    }
  1807. /*
  1808.    while (count-- > 0) {
  1809.       if (*s >= 'a' && *s <= 'z')
  1810.          *s++ &= 0xdf;
  1811.    }
  1812. */
  1813. }
  1814.  
  1815.  
  1816. /*
  1817.  * Name:    fix_uue_asm
  1818.  * Purpose: To fix EBCDIC ==> ASCII translation problem
  1819.  * Date:    June 5, 1991
  1820.  * Passed:  s:    the starting point
  1821.  *          count: number of characters to convert (unsigned)
  1822.  * Returns: none
  1823.  * Notes:   This function goes faster if machine works with WORDs.  See if
  1824.  *           first BYTE in string is WORD aligned.  If it is not, get first
  1825.  *           BYTE in string then the rest of string is WORD aligned.
  1826.  *
  1827.  *           We need to check the three characters that don't pass the
  1828.  *           translation correctly:
  1829.  *
  1830.  *
  1831.  *
  1832.  *          The pointer should have been normalized, using the nptos, as
  1833.  *          this function does not handle segment wrap.  One could safely
  1834.  *          pass a count of 0xFFF0 if the pointer has been normalized to
  1835.  *          a segment.
  1836.  *
  1837.  *          ax, ah, al  = characters from string
  1838.  *          bl          = 0x5d
  1839.  *          bh          = 0xd5
  1840.  *          cx          = number of characters to look at, unsigned
  1841.  *          dl          = 0xe5
  1842.  *          ds:si       = far pointer to character string
  1843.  *                        use ds:si so there is no segment override
  1844.  *
  1845.  *          to fix the EBCDIC to ASCII translation problem, three characters
  1846.  *          need to be changed,  0x5d -> 0x7x, 0xd5 -> 0x5b, 0xe5 -> 0x5d
  1847.  */
  1848. void fix_uue_asm( text_ptr s, unsigned count )
  1849. {
  1850.    _asm {
  1851.         push    ds              ; save ds on stack
  1852.         push    si              ; save si on stack
  1853.  
  1854.         mov     cx, WORD PTR count      ; load count in cx
  1855.         jcxz    get_out                 ; 1st, if count == 0 then do nothing
  1856.         mov     si, WORD PTR s          ; load OFFSET of s
  1857.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  1858.         mov     ds, ax
  1859.         or      si, si          ; is offset of string == NULL or 0?
  1860.         jne     not_null        ; no, do string stuff
  1861.         or      ax, ax          ; is segment of string == NULL or 0?
  1862.         je      get_out         ; yes, don't upper case a NULL string
  1863.         ALIGN   2
  1864. not_null:
  1865.         mov     bl, 0x5d        ; put the check characters in registers
  1866.         mov     bh, 0xd5
  1867.         mov     dl, 0xe5
  1868.         mov     ax, si          ; move offset of si to ax
  1869.         shr     ax, 1           ; shift right into carry flag
  1870.         jnc     top             ; is string WORD aligned?
  1871.         mov     al, BYTE PTR [si]       ; no, get a BYTE
  1872.  
  1873.         cmp     al, bl          ; is al == 0x5d
  1874.         jne     check_d5        ;
  1875.         mov     al, 0x7c        ; 0x5d -> 0x7c
  1876.         jmp     SHORT contin
  1877.         ALIGN   2
  1878. check_d5:
  1879.         cmp     al, bh          ; is al == 0xd5
  1880.         jne     check_e5        ;
  1881.         mov     al, 0x5b        ; 0xd5 -> 0x5b
  1882.         jmp     SHORT contin
  1883.         ALIGN   2
  1884. check_e5:
  1885.         cmp     al, dl          ; is al == 0xe5
  1886.         jne     word_align      ;
  1887.         mov     al, 0x5d        ; 0xe5 -> 0x5d
  1888.         ALIGN   2
  1889. contin:
  1890.         mov     BYTE PTR [si], al       ; store the character or BYTE
  1891.         ALIGN   2
  1892. word_align:
  1893.         inc     si              ; inc the string pointer - now WORD aligned
  1894.         dec     cx              ; decrement the character count
  1895.         jcxz    get_out         ; if count or cx == 0 then we're done
  1896.         ALIGN   2
  1897. top:
  1898.         mov     ax, WORD PTR [si]       ; string is WORD aligned, get two BYTEs
  1899.         cmp     al, bl          ; is al == 0x5d
  1900.         jne     lo_check_d5     ;
  1901.         mov     al, 0x7c        ; 0x5d -> 0x7c
  1902.         jmp     SHORT check_hi
  1903.         ALIGN   2
  1904. lo_check_d5:
  1905.         cmp     al, bh          ; is al == 0xd5
  1906.         jne     lo_check_e5     ;
  1907.         mov     al, 0x5b        ; 0xd5 -> 0x5b
  1908.         jmp     SHORT check_hi
  1909.         ALIGN   2
  1910. lo_check_e5:
  1911.         cmp     al, dl          ; is al == 0xe5
  1912.         jne     check_hi        ;
  1913.         mov     al, 0x5d        ; 0xe5 -> 0x5d
  1914.         ALIGN   2
  1915. check_hi:
  1916.         dec     cx              ; decrement the character count
  1917.         jcxz    clean_up        ; if count or cx == 0 then we're done, clean_up
  1918.  
  1919.         cmp     ah, bl          ; is ah == 0x5d
  1920.         jne     hi_check_d5     ;
  1921.         mov     ah, 0x7c        ; 0x5d -> 0x7c
  1922.         jmp     SHORT save_word
  1923.         ALIGN   2
  1924. hi_check_d5:
  1925.         cmp     ah, bh          ; is ah == 0xd5
  1926.         jne     hi_check_e5     ;
  1927.         mov     ah, 0x5b        ; 0xd5 -> 0x5b
  1928.         jmp     SHORT save_word
  1929.         ALIGN   2
  1930. hi_check_e5:
  1931.         cmp     ah, dl          ; is ah == 0xe5
  1932.         jne     save_word       ;
  1933.         mov     ah, 0x5d        ; 0xe5 -> 0x5d
  1934.         ALIGN   2
  1935.  
  1936. save_word:
  1937.         mov     WORD PTR [si], ax       ; else, save changes
  1938.         dec     cx              ; decrement the count
  1939.         jcxz    get_out         ; if count or cx == 0 then we're done, get out
  1940.         inc     si              ; increment the pointer to next word
  1941.         inc     si
  1942.         jmp     SHORT top       ; look at next WORD
  1943.         ALIGN   2
  1944. clean_up:
  1945.         mov     WORD PTR [si], ax       ; else, save changes then we're done
  1946.         ALIGN   2
  1947. get_out:
  1948.         pop     si              ; get back si from stack
  1949.         pop     ds              ; get back ds from stack
  1950.    }
  1951. /*
  1952.    while (count-- > 0) {
  1953.       if (*s >= 'a' && *s <= 'z')
  1954.          *s++ &= 0xdf;
  1955.    }
  1956. */
  1957. }
  1958.  
  1959.  
  1960. /*
  1961.  * Name:    strip_asm
  1962.  * Purpose: To strip bit 7 from characters
  1963.  * Date:    June 5, 1991
  1964.  * Passed:  s:    the starting point, which should be normalized to a segment
  1965.  *          count: number of characters to strip (unsigned)
  1966.  *                 count should not be greater than 0xfff0
  1967.  * Returns: none
  1968.  * Notes:   This function goes faster if machine works with WORDs.  See if
  1969.  *           first BYTE in string is WORD aligned.  If it is not, get first
  1970.  *           BYTE in string then the rest of string is WORD aligned.
  1971.  *
  1972.  *          The pointer should have been normalized, using the nptos, as
  1973.  *          this function does not handle segment wrap.
  1974.  *
  1975.  *          ax, ah, al  = characters from string
  1976.  *          bl          = 01111111 or 0x7f to strip the hi bit from characters
  1977.  *          cx          = number of characters to look at
  1978.  *          ds:si       = far pointer to character string
  1979.  *                        use ds:si so there is no segment override
  1980.  */
  1981. void strip_asm( text_ptr s, unsigned count )
  1982. {
  1983.    _asm {
  1984.         push    ds              ; save ds on stack
  1985.         push    si              ; save si on stack
  1986.  
  1987.         mov     cx, WORD PTR count      ; load count in cx
  1988.         jcxz    get_out                 ; 1st, if count == 0 then do nothing
  1989.         mov     si, WORD PTR s          ; load OFFSET of s
  1990.         mov     ax, WORD PTR s+2        ; load SEGMENT of s
  1991.         mov     ds, ax
  1992.         or      si, si          ; is offset of string == NULL or 0?
  1993.         jne     not_null        ; no, do string stuff
  1994.         or      ax, ax          ; is segment of string == NULL or 0?
  1995.         je      get_out         ; yes, don't upper case a NULL string
  1996.         ALIGN   2
  1997. not_null:
  1998.         mov     bl, 0x7f        ; turn all bits except high bit in bl
  1999.         mov     ax, si          ; move offset of si to ax
  2000.         shr     ax, 1           ; shift right into carry flag
  2001.         jnc     top             ; is string WORD aligned?
  2002.         mov     al, BYTE PTR [si]       ; no, get a BYTE
  2003.         and     al, bl          ; strip the high bit
  2004.         mov     BYTE PTR [si], al       ; store the character or BYTE
  2005. word_align:
  2006.         inc     si              ; inc the string pointer - now WORD aligned
  2007.         dec     cx              ; dec the character count
  2008.         jcxz    get_out         ; if count or cx == 0 then we're done
  2009.         ALIGN   2
  2010. top:
  2011.         mov     ax, WORD PTR [si]       ; string is WORD aligned, get two BYTEs
  2012.         and     al, bl          ; strip the hi bit from the lo byte
  2013.         dec     cx              ; decrement the count
  2014.         jcxz    clean_up        ; if count or cx == 0 then let's clean up
  2015.         and     ah, bl          ; strip the hi bit from the hi byte
  2016.         mov     WORD PTR [si], ax       ; save changes
  2017.         dec     cx              ; decrement the count
  2018.         jcxz    get_out         ; if count or cx == 0 then we're done
  2019.         inc     si              ; increment the pointer to next word
  2020.         inc     si
  2021.         jmp     SHORT top       ; look at next WORD
  2022.         ALIGN   2
  2023. clean_up:
  2024.         mov     WORD PTR [si], ax       ; else, save changes then we're done
  2025.         ALIGN   2
  2026. get_out:
  2027.         pop     si              ; get back si from stack
  2028.         pop     ds              ; get back ds from stack
  2029.    }
  2030. /*
  2031.    while (count-- > 0) {
  2032.       if (*s >= 'a' && *s <= 'z')
  2033.          *s++ &= 0xdf;
  2034.    }
  2035. */
  2036. }
  2037.  
  2038.  
  2039. /*
  2040.  * Name:    get_fattr
  2041.  * Purpose: To get dos file attributes
  2042.  * Date:    December 26, 1991
  2043.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2044.  *          fattr: pointer to file attributes
  2045.  * Returns: 0 if successfull, non zero if not
  2046.  * Notes:   Uses the DOS function to get file attributes.  I really didn't
  2047.  *           like the file attribute functions in the C library:  fstat() and
  2048.  *           stat() or access() and chmod().
  2049.  *           FYI, File Attributes:
  2050.  *              0x00 = Normal.  Can be read or written w/o restriction
  2051.  *              0x01 = Read-only.  Cannot be opened for write; a file with
  2052.  *                     the same name cannot be created.
  2053.  *              0x02 = Hidden.  Not found by directory search.
  2054.  *              0x04 = System.  Not found by directory search.
  2055.  *              0x08 = Volumn Label.
  2056.  *              0x10 = Directory.
  2057.  *              0x20 = Archive.  Set whenever the file is changed, or
  2058.  *                     cleared by the Backup command.
  2059.  *           Return codes:
  2060.  *              0 = No error
  2061.  *              1 = AL not 0 or 1
  2062.  *              2 = file is invalid or does not exist
  2063.  *              3 = path is invalid or does not exist
  2064.  *              5 = Access denied
  2065.  */
  2066. int  get_fattr( char far *fname, int *fattr )
  2067. {
  2068. int rc;                 /* return code */
  2069. int attr;
  2070.  
  2071.    _asm {
  2072.         push    ds
  2073.         mov     dx, WORD PTR fname      ; get OFFSET of filename string
  2074.         mov     ax, WORD PTR fname+2    ; get SEGMENT of filename string
  2075.         mov     ds, ax                  ; put SEGMENT in ds
  2076.         mov     ax, 0x4300              ; function:  get file attributes
  2077.         int     0x21                    ; DOS interrupt
  2078.         pop     ds
  2079.  
  2080.         jc      an_error                ; save the error code from get attr
  2081.         xor     ax, ax                  ; if no carry, no error
  2082.         jmp     SHORT get_out           ; lets get out
  2083. an_error:
  2084.         xor     cx, cx                  ; if error, then zero out cx - attrs
  2085. get_out:
  2086.         mov     WORD PTR rc, ax         ; ax contains error number on error
  2087.         mov     WORD PTR attr, cx       ; cx contains file attributes
  2088.    }
  2089.    *fattr = attr;
  2090.    if (ceh.flag == ERROR)
  2091.       rc = ERROR;
  2092.    return( rc );
  2093. }
  2094.  
  2095.  
  2096. /*
  2097.  * Name:    set_fattr
  2098.  * Purpose: To set dos file attributes
  2099.  * Date:    December 26, 1991
  2100.  * Passed:  fname: ASCIIZ file name.  Null terminated file name
  2101.  *          fattr: file attributes
  2102.  * Returns: 0 if successfull, non zero if not
  2103.  * Notes:   Uses the DOS function to get file attributes.
  2104.  *           Return codes:
  2105.  *              0 = No error
  2106.  *              1 = AL not 0 or 1
  2107.  *              2 = file is invalid or does not exist
  2108.  *              3 = path is invalid or does not exist
  2109.  *              5 = Access denied
  2110.  */
  2111. int  set_fattr( char far *fname, int fattr )
  2112. {
  2113. int rc;                 /* return code */
  2114.  
  2115.    _asm {
  2116.         push    ds
  2117.         mov     dx, WORD PTR fname      ; get OFFSET of filename string
  2118.         mov     ax, WORD PTR fname+2    ; get SEGMENT of filename string
  2119.         mov     ds, ax                  ; put SEGMENT in ds
  2120.         mov     cx, WORD PTR fattr      ; cx contains file attributes
  2121.         mov     ax, 0x4301              ; function:  get file attributes
  2122.         int     0x21                    ; DOS interrupt
  2123.         pop     ds
  2124.  
  2125.         jc      get_out                 ; save the error code from get attr
  2126.         xor     ax, ax                  ; if no carry, no error
  2127. get_out:
  2128.         mov     WORD PTR rc, ax         ; ax contains error number on error
  2129.    }
  2130.    if (ceh.flag == ERROR)
  2131.       rc = ERROR;
  2132.    return( rc );
  2133. }
  2134.  
  2135.  
  2136. /*
  2137.  * Name:    get_current_directory
  2138.  * Purpose: get current directory
  2139.  * Date:    February 13, 1992
  2140.  * Passed:  path:  pointer to buffer to store path
  2141.  *          drive: drive to get current directory
  2142.  * Notes:   use simple DOS interrupt
  2143.  */
  2144. int  get_current_directory( char far *path, int drive )
  2145. {
  2146. int rc;
  2147.  
  2148.    _asm {
  2149.         push    si                      ; save register vars if any
  2150.         push    ds                      ; save ds
  2151.  
  2152.         mov     dx, WORD PTR drive      ; dl = drive, 0 = default, 1 = a, etc..
  2153.         mov     si, WORD PTR path       ; get OFFSET of path
  2154.         mov     ax, WORD PTR path+2     ; get SEGMENT of path
  2155.         mov     ds, ax                  ; put it in ds
  2156.         mov     ah, 0x47                ; function 0x47 == get current dir
  2157.         int     0x21                    ; standard DOS interrupt
  2158.         xor     ax, ax                  ; zero out ax, return OK if no error
  2159.         jnc     no_error                ; if carry set, then an error
  2160.         mov     ax, -1                  ; return -1 if error
  2161. no_error:
  2162.         pop     ds                      ; get back ds
  2163.         pop     si                      ; get back si
  2164.         mov     WORD PTR rc, ax         ; save return code
  2165.    }
  2166.    if (ceh.flag == ERROR)
  2167.       rc = ERROR;
  2168.    return( rc );
  2169. }
  2170.  
  2171.  
  2172. /*
  2173.  * Name:    set_current_directory
  2174.  * Purpose: set current directory
  2175.  * Date:    February 13, 1992
  2176.  * Passed:  new_path: directory path which may include drive letter
  2177.  * Notes:   use simple DOS interrupt
  2178.  */
  2179. int  set_current_directory( char far *new_path )
  2180. {
  2181. int rc;
  2182.  
  2183.    _asm {
  2184.         push    ds                      ; save ds
  2185.  
  2186.         mov     dx, WORD PTR new_path   ; get OFFSET of new_path
  2187.         mov     ax, WORD PTR new_path+2 ; get SEGMENT of new_path
  2188.         mov     ds, ax                  ; put it in ds
  2189.         mov     ah, 0x3b                ; function 0x3b == set current dir
  2190.         int     0x21                    ; standard DOS interrupt
  2191.         xor     ax, ax                  ; zero out ax, return OK if no error
  2192.         jnc     no_error                ; if carry set, then an error
  2193.         mov     ax, -1                  ; return -1 if error
  2194. no_error:
  2195.         pop     ds                      ; get back ds
  2196.         mov     WORD PTR rc, ax         ; save return code
  2197.    }
  2198.    if (ceh.flag == ERROR)
  2199.       rc = ERROR;
  2200.    return( rc );
  2201. }
  2202.  
  2203.  
  2204. /*
  2205.  * Name:    hlight_line
  2206.  * Date:    July 21, 1991
  2207.  * Passed:  x:     column to begin hi lite
  2208.  *          y:     line to begin hi lite
  2209.  *          lgth:  number of characters to hi lite
  2210.  *          attr:  attribute color
  2211.  * Notes:   The attribute byte is the hi byte.
  2212.  */
  2213. void hlight_line( int x, int y, int lgth, int attr )
  2214. {
  2215. int off;
  2216. void far *screen_ptr;
  2217.  
  2218.    screen_ptr = (void far *)g_display.display_address;
  2219.    off = y * 160 + 2 * x + 1;  /* add one - so it points to attribute byte */
  2220.    _asm {
  2221.         push    di              ; save di
  2222.  
  2223.         mov     cx, lgth        ; number of characters to change color
  2224.  
  2225.         mov     di, WORD PTR screen_ptr ; get destination - video memory
  2226.         add     di, off                 ; add offset
  2227.         mov     ax, WORD PTR screen_ptr+2
  2228.         mov     es, ax
  2229.         mov     ax, attr        ; attribute
  2230. lite_len:
  2231.         stosb                   ; store a BYTE
  2232.         inc     di              ; skip over character to next attribute
  2233.         loop    lite_len        ; change next attribute
  2234.         pop     di              ; restore di
  2235.    }
  2236. }
  2237.  
  2238.  
  2239. /*
  2240.  * Name:    cls
  2241.  * Purpose: clear screen
  2242.  * Date:    June 5, 1991
  2243.  * Notes:   Call the video BIOS routine to clear the screen.
  2244.  */
  2245. void cls( void )
  2246. {
  2247. int line;
  2248.  
  2249.    line = g_display.nlines+1;
  2250.    _asm {
  2251.         xor     ch, ch                  ; starting row in ch = 0
  2252.         xor     cl, cl                  ; starting column in cl = 0
  2253.         mov     ax, WORD PTR line       ; get ending row
  2254.         mov     dh, al                  ; put it in dh
  2255.         mov     dl, 79                  ; ending column in dl = 79
  2256.         mov     bh, 7                   ; attribute in bh  = 7 (normal)
  2257.         mov     al, 0                   ; get number of lines
  2258.         mov     ah, 6                   ; get function number
  2259.         push    bp                      ; some BIOS versions wipe out bp
  2260.         int     0x10
  2261.         pop     bp
  2262.    }
  2263. }
  2264.  
  2265.  
  2266. /*
  2267.  * Name:    set_cursor_size
  2268.  * Purpose: To set cursor size according to insert mode.
  2269.  * Date:    June 5, 1991
  2270.  * Passed:  csize:  desired cursor size
  2271.  * Notes:   use the global display structures to set the cursor size
  2272.  */
  2273. void set_cursor_size( int csize )
  2274. {
  2275.    _asm {
  2276.         mov     ah, 1                   ; function 1 - set cursor size
  2277.         mov     cx, WORD PTR csize      ; get cursor size ch:cl == top:bot
  2278.         int     VIDEO_INT               ; video interrupt = 10h
  2279.    }
  2280. }
  2281.  
  2282.  
  2283. /*
  2284.  * Name:    findfirst
  2285.  * Purpose: find the first file matching a pattern using DOS interrupt
  2286.  * Date:    January 6, 1992
  2287.  * Passed:  dta:    disk transfer address
  2288.  *          path:   path to search for files
  2289.  *          f_attr: attributes of files to search for
  2290.  * Notes:   return codes for findfirst:
  2291.  *             0  no error
  2292.  *             2  file is invalid or does not exist
  2293.  *             3  path is invalid or does not exist
  2294.  *            18  no matching directory entry was found
  2295.  *            -1  check the critical error flag for critical errors
  2296.  */
  2297. int  findfirst( DTA far *dta, char far *path, int f_attr )
  2298. {
  2299. void far *old_dta;
  2300. void far *new_dta;
  2301. int rc;
  2302.  
  2303.    new_dta = (void far *)dta;
  2304.    _asm {
  2305.  
  2306. ; save the old dta
  2307.         mov     ah, 0x2f                ; DOS get dta
  2308.         int     0x21                    ; DOS interrupt
  2309.         mov     WORD PTR old_dta, bx    ; save OFFSET of old DTA
  2310.         mov     ax, es
  2311.         mov     WORD PTR old_dta+2, ax  ; save SEGMENT of old DTA
  2312.  
  2313. ; set the new dta
  2314.         push    ds                      ; save ds
  2315.         mov     dx, WORD PTR new_dta    ; get OFFSET of new dta
  2316.         mov     ax, WORD PTR new_dta+2  ; get SEGMENT of new dta
  2317.         mov     ds, ax                  ; put it in ds
  2318.         mov     ah, 0x1a                ; DOS set dta
  2319.         int     0x21                    ; DOS interrupt
  2320.         pop     ds                      ; get back ds
  2321.  
  2322. ; find first matching file
  2323.         push    ds                      ; save ds
  2324.         mov     cx, WORD PTR f_attr     ; file attributes to search for
  2325.         mov     dx, WORD PTR path       ; get OFFSET of path
  2326.         mov     ax, WORD PTR path+2     ; get SEGMENT of path
  2327.         mov     ds, ax                  ; put it in ds
  2328.         mov     ah, 0x4e                ; DOS find first file
  2329.         int     0x21                    ; DOS interrupt
  2330.         pop     ds                      ; get back ds
  2331.  
  2332. ; save the return code
  2333.         jc      an_error                ; carry is set if an error occured
  2334.         xor     ax, ax                  ; zero out ax, return OK if no error
  2335. an_error:
  2336.         mov     WORD PTR rc, ax         ; save the return code
  2337.  
  2338. ; get back old dta
  2339.         push    ds                      ; save ds
  2340.         mov     dx, WORD PTR old_dta    ; get OFFSET of old dta
  2341.         mov     ax, WORD PTR old_dta+2  ; get SEGMENT of old dta
  2342.         mov     ds, ax                  ; put it in ds
  2343.         mov     ah, 0x1a                ; DOS set dta
  2344.         int     0x21                    ; DOS interrupt
  2345.         pop     ds                      ; get back ds
  2346.    }
  2347.    if (ceh.flag == ERROR)
  2348.       rc = ERROR;
  2349.    return( rc );
  2350. }
  2351.  
  2352.  
  2353. /*
  2354.  * Name:    findnext
  2355.  * Purpose: find the next file matching a pattern using DOS interrupt
  2356.  * Date:    January 6, 1992
  2357.  * Passed:  dta:  disk transfer address
  2358.  * Notes:   findfirst() MUST be called before calling this function.
  2359.  *          return codes for findnext:
  2360.  *             0  no error
  2361.  *             2  path is invalid or does not exist
  2362.  *            18  no matching directory entry was found
  2363.  *            -1  check the critical error flag for critical errors
  2364.  */
  2365. int  findnext( DTA far *dta )
  2366. {
  2367. void far *old_dta;
  2368. void far *new_dta;
  2369. int rc;
  2370.  
  2371.    new_dta = (void far *)dta;
  2372.    _asm {
  2373.  
  2374. ; save the old dta
  2375.         mov     ah, 0x2f                ; DOS get dta
  2376.         int     0x21                    ; DOS interrupt
  2377.         mov     WORD PTR old_dta, bx    ; save OFFSET of old DTA
  2378.         mov     ax, es
  2379.         mov     WORD PTR old_dta+2, ax  ; save SEGMENT of old DTA
  2380.  
  2381. ; set the new dta
  2382.         push    ds                      ; save ds
  2383.         mov     dx, WORD PTR new_dta    ; get OFFSET of new dta
  2384.         mov     ax, WORD PTR new_dta+2  ; get SEGMENT of new dta
  2385.         mov     ds, ax                  ; put it in ds
  2386.         mov     ah, 0x1a                ; DOS set dta
  2387.         int     0x21                    ; DOS interrupt
  2388.         pop     ds                      ; get back ds
  2389.  
  2390. ; find next matching file
  2391.         mov     ah, 0x4f                ; DOS find first file
  2392.         int     0x21                    ; DOS interrupt
  2393.  
  2394. ; save the return code
  2395.         jc      an_error                ; carry is set if an error occured
  2396.         xor     ax, ax                  ; zero out ax, return OK if no error
  2397. an_error:
  2398.         mov     WORD PTR rc, ax         ; save the return code
  2399.  
  2400. ; get back old dta
  2401.         push    ds                      ; save ds
  2402.         mov     dx, WORD PTR old_dta    ; get OFFSET of old dta
  2403.         mov     ax, WORD PTR old_dta+2  ; get SEGMENT of old dta
  2404.         mov     ds, ax                  ; put it in ds
  2405.         mov     ah, 0x1a                ; DOS set dta
  2406.         int     0x21                    ; DOS interrupt
  2407.         pop     ds                      ; get back ds
  2408.    }
  2409.    if (ceh.flag == ERROR)
  2410.       rc = ERROR;
  2411.    return( rc );
  2412. }
  2413.